在 Spring Boot 中自动装配参数化构造函数

kri*_*hna 4 constructor dependency-injection parameter-passing spring-boot

在参数化构造函数中传递值时,我无法自动装配 bean。

如何使用 SpringBoot 调用参数化构造函数?

@Component
public class MainClass {

    public void someTask() {
        AnotherClass obj = new AnotherClass(1, 2);
    }

}
//Replace the new AnotherClass(1, 2) using Autowire?

@Component
public class AnotherClass {
    private int number,age;

    public AnotherClass(int number, int age) {
        super();
        this.number = number;
        this.age = age;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想自动装配“AnotherClass”bean。如何删除new AnotherClass(1, 2); 我如何放置@Autowire在这里?

Bwv*_*all 9

您需要在构造函数中指定此 bean:

@Component
public class MainClass {

    private final AnotherClass anotherClass;

    // this annotation is NOT required if there is only 1 constructor, shown for clarity.
    @Autowired
    MainClass(AnotherClass anotherClass) {
        this.anotherClass = anotherClass;
    }
    public void someTask() {
        // anotherClass is already instantiated by the time you get here.
    }

}
Run Code Online (Sandbox Code Playgroud)

选项 1:直接允许AnotherClass使用组件扫描创建。

现在,为了让 Spring 能够构造AnotherClass为 bean,您需要以“Spring 方式”告诉它从何处获取值:

@Component
public class AnotherClass {
    private final int number,age;

    // also not needed if this is the only constructor.
    @Autowired
    public AnotherClass(
// @Value is a spring annotation to provide spring the value it needs for this parameter.
                        @Value("${property.number:0}") int number, 
                        @Value("${property.age:0}") int age) {
        this.number = number;
        this.age = age;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样做的目的是拉取 2 个属性,property.number然后property.age来自application.properties| application.yml对于这些整数的值。

您需要确保这两个类都在组件扫描路径上,否则 spring boot 将不会尝试生成这些类的 bean。


选项 2:使用配置类来制作AnotherClassbean

@Configuration
public class MyConfigurationClass {

    @Bean
    public AnotherClass anotherClass {
        return new AnotherClass(1,2)
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,你就不会标注AnotherClass@Component


选项 3:使用本博客中的自定义工厂方法。

同样,这一战略,没有注释AnotherClass@Component

@Configuration
public class MyConfigurationClass {

    @Bean
    public BiFunction<Integer, Integer, MyPrototype> myPrototypeFactory() {
        return start, age -> anotherClass(start, age);
    }

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public AnotherClass anotherClass(Integer start, Integer age) {
        if (start == null || age == null) {
            throw new IllegalArgumentException("start was: " + start + ", age was: " + age + ". Neither can be null!");
        }
        return new AnotherClass(start,age);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

@Component
public class MainClass {

    private final BiFunction<Integer, Integer, AnotherClass> anotherClassFactory;

    // this annotation is NOT required if there is only 1 constructor, shown for clarity.
    @Autowired
    MainClass(BiFunction<Integer, Integer, AnotherClass> anotherClassFactory) {
        this.anotherClassFactory = anotherClassFactory;
    }
    public void someTask() {
        AnotherClass ac = anotherClassFactory.apply(1,2);
        // do something with your new AnotherClass
    }

}
Run Code Online (Sandbox Code Playgroud)

选项 4:使用ObjectProvider(自 Spring 4.3 起),如本博文中所述

同样,这一战略,没有注释AnotherClass@Component

@Configuration
public class MyConfiguration {
    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public AnotherClass createAnotherClass(Integer start, Integer age) {
        return new AnotherClass(start, age);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

@Component
public class MainClass {

    private final ObjectProvider<AnotherClass> anotherClassProvider;

    // this annotation is NOT required if there is only 1 constructor, shown for clarity.
    @Autowired
    MainClass(ObjectProvider<AnotherClass> anotherClassProvider) {
        this.anotherClassProvider = anotherClassProvider;
    }
    public void someTask() {
        // may need to cast the result of '.getObject()'
        AnotherClass ac = anotherClassProvider.getObject(/*start*/ 1, /*age*/ 2);
        // do something with your new AnotherClass
    }

}
Run Code Online (Sandbox Code Playgroud)