bean类是否可以在其中实例化另一个类,如果/应该如何避免它?

时间:2018-02-14 19:06:45

标签: java spring dependency-injection javabeans spring-loaded

假设bean在这里注册。

@Configuration
public class configuration{

    @Bean(name = "MyClass")
    public MyClass getMyClass(@Value("avalue") final String s){
        return new MyClass(s);
        }
    }
}

并且该类在内部实例化了另一个类,如下所示(两者都不需要注释?)

public class MyClass{
    MyOtherClass myOtherClass;
    public MyClass(String s){
        this.myOtherClass = new MyOtherClass(s);
    }
}

public class MyOtherClass{
    String s;
    public MyOtherClass(String s){
        this.s = s;
    }
}

这种机制如何运作?在bean注入中实例化一个新实例是否安全?这样做有什么好处或缺点?

如果我们通过将MyOtherClass变成bean来避免使用它,那会是这样吗? (主要是关于:@Autowired和getMyclass()是否占据了正确的位置,或者它是多余的?)

@Configuration
public class configuration{

    @Bean(name = "MyOtherClass")
    public MyOtherClass getMyOtherClass(@Value("avalue") final String s){
        return new MyOtherClass(s);
        }
    }

    @Bean(name = "MyClass")
    public MyClass getMyClass(MyClass myClass){
    //I was told the input should be myClass not myOtherClass,
    //and the return is myClass not new MyClass(myOtherClass);
    //since it's already autowired. Is that correct?
    //What if the configuration.java and MyClass.java are in different project?
        return myClass;
        }
    }
}

@Component
public class MyClass{
    MyOtherClass myOtherClass;

    @Autowired
    public MyClass(MyOtherClass myOtherClass){
        this.myOtherClass = myOtherClass;
    }
}

public class MyOtherClass{
    String s;
    public MyOtherClass(String s){
        this.s = s;
    }
}

2 个答案:

答案 0 :(得分:1)

在bean注入中实例化一个新实例是否安全?

是。但是,新实例不是由Spring管理的。 (对不起,如果那是显而易见的。)

但也许更重要的是与Spring无关,这样做:

public class MyClass{
    MyOtherClass myOtherClass;
    public MyClass(String s){
        this.myOtherClass = new MyOtherClass(s);
    }
}

很难进行单元测试,因为没有简单的方法来模拟myOtherClass

与Spring无关,重构使用IoC以便于单元测试:

public class MyClass{
    private final MyOtherClass myOtherClass;
    public MyClass(MyOtherClass myOtherClass){
        this.myOtherClass = myOtherClass;
    }
}

将类配置为Spring bean,但没有MyOtherClass也作为bean:

@Configuration
public class Configuration{

    private MyOtherClass getMyOtherClass(final String s){
        return new MyOtherClass(s);
        }
    }

    @Bean(name = "MyClass")
    public MyClass getMyClass(@Value("avalue") final String s){
        return new MyClass(getMyOtherClass(s));
        }
    }
}

你发布的关于@Component和@Autowire的内容可行,但听起来你想避免将MyOtherClass暴露为bean。

答案 1 :(得分:1)

如果您不想公开MyOtherClass并控制其创建实例,可以使用第一种方法:

...
public MyClass(String s) {
    this.myOtherClass = new MyOtherClass(s);
}

它是安全的,但它不是依赖注入:MyOtherClass不是由Spring管理的,所以你将无法使用@Autowired将其注入其他bean或注入其他spring托管类到MyOtherClass。另外,正如安德鲁所提到的,模仿MyOtherClass变得不可能。

如果在Spring上下文中将MyOtherClass注册为bean是正常的,那么最简单的方法是使用@Component注释两个类并让Spring完成其工作(在这种情况下,您应该使用{{ 1}}帮助Spring自动检测你的类):

@ComponentScan

或者,使用@Component class MyClass { MyOtherClass myOtherClass; @Autowired public MyClass(MyOtherClass myOtherClass){ this.myOtherClass = myOtherClass; } } @Component class MyOtherClass { String s; public MyOtherClass(@Value("avalue") final String s){ this.s = s; } } (如果@BeanConfig.java位于不同的项目中,这将有效):

MyClass.java

注意:如果您已使用

在Spring上下文中注册了@Configuration public class Config { @Value("avalue") private String s; @Bean(name = "myClass") public MyClass getMyClass(){ return new MyClass(getMyOtherClass()); } @Bean(name = "myOtherClass") public MyOtherClass getMyOtherClass() { return new MyOtherClass(s); } }
MyClass

然后你不需要再通过

再做一次
@Component
public class MyClass {
    ...
}