我目前正在开发一个弹簧启动应用程序,它通过以下方式将一些bean连接在一起(大大简化的示例):
Component
然而,实际的bean需要比此处所示更多的配置和设置,并且在使用内部Lazy Bean方法时,它在PlayingFieldByBeans类中需要很多行代码。所以我使用@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));
});
}
}
注释创建了一种不同的连接方式:
@Component
public class PlayerComponent {
@Autowired
private ShoesComponent shoesComponent;
public Player player(String name) {
return new Player(name, shoesComponent.shoes());
}
}
PlayerComponent类如下所示:
@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");
}
}
ShoesComponent与PlayerComponent类非常相似。
为了维护和TDD的目的,我不确定在这里使用spring框架最合适的方法是什么。
问题
鉴于Player和Shoes bean只需要一行初始化(多个设置,对其他bean的多个依赖等),设计和连接它们的最佳方法是什么?
修改 - 根据建议
添加了一个配置类来捆绑bean:
@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));
});
}
}
匹配的执行类:
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
Re使用相同的第一个bean,所以它似乎没有创建一个新的
abstract class AbstractEventFilter {
private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
private final String filterName = getClass().getSimpleName();
protected abstract Predicate<IEvent> isEligible();
private Predicate<IEvent> internalIsEligible() {
return iEvent -> {
boolean res = isEligible().test(iEvent);
if (!res) {
logger.info("event " + iEvent.toString() + " filtered by " + filterName);
}
return res;
};
}
public List<IEvent> getFilteredEvents(final List<IEvent> events) {
return events.stream().filter(internalIsEligible()).collect(Collectors.toList());
}
}
答案 0 :(得分:1)
如Andriy Slobodyanyk所述,一个解决方案是改变播放器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();
}
});
}
}