如何解决使用@Configuration在Spring中创建bean的集合
| 我如何创建一个豆类集合,这些类将由Spring使用带有@Configuration批注的类进行适当地管理。 我想做这样的事情:@Configuration
public Config {
@Autowired
private SomeConfiguration config;
@Bean
public List<MyBean> myBeans() {
List<MyBean> beans = new ArrayList<MyBean>();
for (Device device : config.getDevices()) {
beans.add(new MyBean(device));
}
return beans;
}
}
但是不会对MyBean实例进行后期处理。因此,不会调用它们的@Autowired方法,也不会将bean注册为mbeans等。但是可以访问该列表,以便我可以自动装配MyBean对象的List。
我不能使用类似:
@Configuration
public Config {
@Autowired
private SomeConfiguration config;
@Bean
public MyBean myBean1() { ... }
@Bean
public MyBean myBean2() { ... }
}
由于在运行时之前不知道MyBean实例的数量。我要这样做的原因是因为我们正在控制具有可变数量组件的物理机。我希望每个组件有一个bean。
我目前正在通过使用像这样的BeanFactoryPostProcessor实现我们的目标:
@Component
public class MyBeansFactoryPostProcessor implements BeanFactoryPostProcessor {
@Autowired
private SomeConfiguration config;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeanException {
for (Device device : config.getDevices()) {
createAndRegister(BeanDefinitionRegistry) beanFactory,device);
}
}
private void createAndRegister(BeanDefinitionRegistry registry,Device device) {
register.registerBeanDefinition(\"device\" + device.getId(),BeanDefinitionBuilder.genericBeanDefinition(MyBean.class).addConstructorArgValue(device).getBeanDefinition());
}
}
但这感觉就像是一个非常丑陋的骇客。
解决方法
为了注入您的MyBean列表,请尝试@Resource而不是@Autowired。例如
@Resource
public List<MyBean> myBeans
,您可以使用支持SmartLifecycle
的ConfigurableListableBeanFactory
,因此,如果在应用程序完全初始化之前注册Bean,它将为您和其他后期处理步骤调用start()
。
但是-如果在spring初始化后调用beanFactory.registerSingleton
,则您将需要手动调用start()
-尽管您的bean仍完全连接到生命周期管理中,但光明的一面,当应用程序上下文关闭时spring会为您调用stop()
。
@Autowired
private ConfigurableListableBeanFactory beanFactory;
@Bean
public List<MyBean> myBeansList() {
List<MyBean> mylist; // Construct your list dynamically
while(myCondition) {
MyBean bean;
// Manually register each instance with Spring
beanFactory.registerSingleton(\"unique-name-for-this-bean\",bean);
}
// Return your list as a bean so you can still autowire the list of beans
// but each bean has already been manually added to the context
return mylist;
}
,@Configuration
不能为每个方法(AFAIK)定义一个以上的bean。因此,您将不得不继续使用BFPP或使用ApplicationContect.getAutowireCapableBeanFactory().autowire(object);
,我相信在这种情况下的另一种选择是以以下方式使用@PostConstruct:
@Configuration
public Config {
@Autowired
private SomeConfiguration config;
List<MyBean> beans = new ArrayList<MyBean>();
@Bean
public List<MyBean> myBeans() {
return beans;
}
@PostConstruct
public void init() {
for (Device device : config.getDevices()) {
beans.add(new MyBean(device));
}
}
}
@PostConstruct批注对于初始化属性很有用。它保证带注释的方法在创建bean时仅被调用一次。
如果我错了纠正我
,MyBeans
不会进行后期处理,因为它们是由new
创建的,并且未由Spring容器初始化。
您需要使用原型bean,每个组件提出的请求都有一个新bean的实例。
您将需要标记MyBean(Device device)
bean声明,例如
@Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
然后调用它,而不是在填充beans
的地方使用new
。
,我最终扩展了ArrayList。
@Configuration
public class Config {
@Autowired
private SomeConfiguration config;
@Bean
public List<MyBean> myBeans() {
List<MyBean> beans = new MyBeanList();
for (final Device device : config.getDevices()) {
beans.add(new MyBean(device));
}
return beans;
}
private static class MyBeanList extends ArrayList<MyBean> {
@PostConstruct
public void init() {
this.forEach(bean -> bean.init());
}
@PreDestroy
public void close() {
this.forEach(bean -> bean.close());
}
}
}
当然,这是骇人听闻的,但是比发问者的方法丑陋得多。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。