我目前正在开发一个 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));
});
}
}
Re 使用相同的第一个 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
正如 Andriy Slobodyanyk 提到的,一种解决方案是更改 Player bean 的范围(如果我们想创建不同的品牌,则稍后更改鞋类)
@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();
}
});
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句