我目前正在开发一个 Spring Boot 应用程序,它通过以下方式将一些 Bean 连接在一起(高度简化的示例):
@Component
@Order(0)
public class PlayingFieldByBeans implements CommandLineRunner {
@Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from lazy beans variant: ");
names.forEach(n -> {
System.out.println(player(n));
});
}
@Bean
@Lazy
public Player player(String name) {
return new Player(name, shoes());
}
@Bean
@Lazy
private Shoes shoes() {
return new Shoes("Adidas");
}
}
然而,实际的 Bean 需要比此处显示的更多的配置和设置,并且在使用内部 Lazy Bean 方法时,在 PlayingFieldByBeans 类中需要相当多的代码行。因此,我创建了一种使用 Component
注释将其连接在一起的不同方式:
@Component
@Order(1)
public class PlayingFieldByComponents implements CommandLineRunner {
@Autowired
private PlayerComponent playerComponent;
@Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
System.out.println(playerComponent.player(n));
});
}
}
PlayerComponent 类如下所示:
@Component
public class PlayerComponent {
@Autowired
private ShoesComponent shoesComponent;
public Player player(String name) {
return new Player(name, shoesComponent.shoes());
}
}
ShoesComponent 与 PlayerComponent 类非常相似。
出于可维护性和 TDD 的目的,我不确定在这里使用 spring 框架的最正确方法是什么。
问题
鉴于 Player 和 Shoes bean 需要的不仅仅是一行初始化(多个设置、对其他 bean 的多个依赖项等),设计和连接它们的最佳方法是什么?
编辑 - 根据建议
添加了一个配置类来捆绑 bean:
@Configuration
public class BeanConfiguration {
@Bean
@Lazy
public Player player(String name) {
return new Player(name, shoes());
}
@Bean
@Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
}
以及匹配的执行类:
@Component
@Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {
@Autowired
private BeanConfiguration beanConfiguration;
@Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
System.out.println(beanConfiguration.player(n));
});
}
}
重新使用相同的第一个 bean,因此它似乎没有创建新的 bean
Printing from component variant:
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
最佳答案
一种解决方案是更改 Player bean 的范围(如果我们想创建不同的品牌,则稍后更改 Shoes),正如 Andriy Slobodyanyk 提到的
@Configuration
public class BeanConfiguration {
@Bean
@Lazy
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Player player(String name) {
return new Player(name, shoes());
}
@Bean
@Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
}
如果上述还不够(因为您提到实际案例场景更加复杂),另一种选择是使用 FactoryBean
public class PlayerFactoryBean implements FactoryBean<Player> {
private String name;
private Shoes shoes;
public void setName(String name) {
this.name = name;
}
public void setShoes(Shoes shoes) {
this.shoes = shoes;
}
@Override
public Player getObject() throws Exception {
//initialization logic goes here
System.out.println("Creating bean using factory");
return new Player(name, shoes);
}
@Override
public Class<Player> getObjectType() {
return Player.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
<小时/>
@Configuration
public class BeanConfiguration {
@Bean
@Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
@Bean
public PlayerFactoryBean playerFactoryBean(){
PlayerFactoryBean pfb = new PlayerFactoryBean();
pfb.setShoes(shoes());
return pfb;
}
}
<小时/>
@Component
@Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {
@Autowired
private PlayerFactoryBean factoryBean;
@Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
try {
factoryBean.setName(n);
System.out.println(factoryBean.getObject());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
关于java - 应用依赖注入(inject)的正确 Spring Boot 方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43559478/