有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java可以让一个bean类实例化内部的另一个类,我们是否应该/如何避免它?

假设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 a 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) 个答案

  1. # 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;
        }
    }
    

    并将该类配置为Springbean,但不将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公开

  2. # 2 楼答案

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

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

    它是安全的,但它不是依赖项注入:MyOtherClass不是由Spring管理的,因此您将无法使用@Autowired将它注入其他bean,或者将其他Spring管理的类注入MyOtherClass。此外,正如Andrew所提到的,模拟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上下文中使用

    @Component
    public class MyClass {
        ...
    }
    

    那你就不必再这样做了

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