【问题标题】:What is the object creation policy in spring frameworkspring框架中的对象创建策略是什么
【发布时间】:2017-08-11 10:38:37
【问题描述】:

我是 Spring 框架的新手,只是在用它做一些有趣的事情。在那期间,我遇到了一个奇怪的输出。我试图调试。但没有得到答案(虽然我没有深入研究框架代码)。

我想做的事:我只是想创建一个User 类的实例。带有值{city = 'Sirsa2', i1 = 12}

我有以下四个代码文件:

IntTest.java

package Task4;

import org.springframework.stereotype.Service;

//Just creating an integer. Since Integer class is final so, I have to extend Number class. So I also needed to override abstract metods. 
@Service
public class IntTest extends Number {
    Integer i1;

    public Integer getI1() {
        return i1;
    }

    public void setI1(Integer i1) {
        this.i1 = i1;
    }

    public IntTest() {
        i1 = 90;
    }
    @Override
    public double doubleValue() {
        return i1.doubleValue();
    }

    @Override
    public float floatValue() {
        return i1.floatValue();
    }

    @Override
    public int intValue() {
        return i1.intValue();
    }

    @Override
    public long longValue() {
        return i1.longValue();
    }
}

Address.java

package Task4;

import org.springframework.stereotype.Service;

@Service
public class Address {
    private String city;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

User.java

package Task4;

import org.springframework.stereotype.Service;

@Service
public class User {

    Address address;
    Integer i1;

    User(Address address, IntTest t1)
    {
        this.address= address;
        i1 = t1.getI1();
        System.out.println("1. Point " + t1.getI1());
    }

    public void getInfo() {
        System.out.println(address.getCity() + " | "+i1.intValue());
    }
}

Config.java

package Task4;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("Task3")
public class Config {}

MainClass.java

package Task4;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainClass {
    public static void main(String args[]) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();
        context.register(Config.class);
        context.refresh();
        Address address1=(Address)context.getBean(Address.class);
        address1.setCity("Sirsa");

        Address address2=(Address)context.getBean(Address.class);
        address2.setCity("Sirsa2");

        IntTest intTest=(IntTest)context.getBean(IntTest.class);
        System.out.println("2. Point " + intTest.getI1());
        intTest.setI1(12);
        System.out.println("3. Point " + intTest.getI1());

        User user=(User) context.getBean(User.class);
        user.getInfo();
    }
}

当我将 MainClass.java 作为 JavaApplication 运行时,我会得到以下输出

1. Point 90
2. Point 90
3. Point 12
Sirsa2 | 90

但期待:

2. Point 90
3. Point 12
1. Point 12
Sirsa2 | 12

我不确定对象是如何创建的。但我认为:

  • 要创建 User 类的对象,正在调用构造函数 User(Address address, IntTest t1)
  • 由于在构造函数中传递的Address 类的对象是address1 变量(因为它的值被打印为'Sirsa2',而不是'Sirsa')。所以我期待IntTest 类的对象应该是i1 变量。
  • 另外,我希望User 类的构造函数应该最后调用。但根据输出情况并非如此。
  • 当我调试它时,我才知道它是在context.refresh(); 中的MainClass.java 中创建对象。但是如何将 City 的值设置为 Sirsa2 而不是将 i1 的值设置为 12。

我正在使用 Eclipse(Oxygen)Java 1.8.0_121spring-framework-4.3.9.RELEASEcommons-logging-1.2

【问题讨论】:

  • 默认情况下,Spring bean 是单例的,这意味着只创建一个 bean 实例,该实例在任何使用它的地方都可以重用。请参阅 Spring Framework 文档中的 Bean scopes
  • @Jesper 感谢您提供此信息。但是为什么没有按照我的期望设置值。我知道我的例外很奇怪。但是spring框架的行为也是如此;)(因为它选择Address的值而不是IntTest的值)
  • 请注意,由于它们是单例,所以只有一个Address 对象,address1address2 都引用同一个对象。你可以做address1.setCity("Sirsa");address2.setCity("Sirsa2"); 行会覆盖它,因为它是同一个对象。同样只有一个IntTest 对象。
  • 由于 spring 在 spring 容器中创建了所有对象。它们首先在应用程序启动期间初始化。之后它将继续注入对象。默认情况下,对象是单例范围,因此它将是整个应用程序都一样,但这没关系。是的,你是对的,它只会像这样工作。

标签: spring


【解决方案1】:

默认情况下,ApplicationContext 实现会在初始化过程中急切地创建和配置所有单例 bean。这是在应用程序启动期间。之后它将继续注入对象。默认情况下,对象是单例范围,因此它将整个应用程序都是一样的。是的,你是对的,它只会像这样工作

http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-lazy-init

When does Spring create instances of objects that are injected

因为System.out.println("1. Point " + t1.getI1());在用户对象的构造函数中,而启动应用程序时spring试图为这个类用户创建对象,构造函数被调用,所以point1被打印出来。

如果你想要以下行为 2. 点 90 3. 第 12 点 1. 第 12 点 西尔萨2 | 12

在你的 bean 上设置 lazy-init="true"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 2016-08-14
    • 2020-04-10
    • 2020-05-30
    • 2012-02-01
    相关资源
    最近更新 更多