一个 bean class 可以在里面实例化另一个 class 吗?if/how 我们应该避免吗?

Can a bean class instantiate another class inside, and if/how should we avoid it?

假设bean在这里注册。

@Configuration
public class configuration{

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

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

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;
    }
}

在 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;
    }
}

并将 class 配置为 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 公开。

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

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

它是安全的,但它不是依赖项注入:MyOtherClass 不受 Spring 管理,因此您将无法使用 [=17= 将其注入到其他 bean 中] 或将其他 spring 管理的 类 注入 MyOtherClass。此外,正如安德鲁所提到的,模拟 MyOtherClass.

变得不可能

如果在 Spring 上下文中将 MyOtherClass 注册为 bean 没问题,那么最简单的方法是将 类 都注释为 @Component 并让 Spring 完成它的工作(在这种情况下你应该使用 @ComponentScan 来帮助 Spring 自动检测你的 类):

@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;
    }
}

或者,使用 @Bean(如果 Config.javaMyClass.java 在不同的项目中,这将有效):

@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);
    }
}

注意:如果您已经使用

在 Spring 上下文中注册 MyClass
@Component
public class MyClass {
    ...
}

那你就不需要再做一次

@Bean(name = "MyClass")
public MyClass getMyClass(MyClass myClass) {
    return myClass;
}