Java 使用@Configuration在Spring中创建bean集合

Java 使用@Configuration在Spring中创建bean集合,java,spring,configuration,collections,annotations,Java,Spring,Configuration,Collections,Annotations,我如何创建一个bean集合,这些bean将由Spring使用带有@Configuration注释的类进行正确管理 我想这样做: @Configuration public Config { @Autowired private SomeConfiguration config; @Bean public List<MyBean> myBeans() { List<MyBean> beans = new ArrayList&

我如何创建一个bean集合,这些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;
    }
}
@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实例的数量在运行之前是未知的。我想这样做的原因是因为我们控制的是一台物理机器,它有可变数量的组件。我希望每个组件有一个bean

我目前通过使用BeanFactory后处理器实现了我们的目标,如下所示:

@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;
    }
}
@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());
    }
}

但是这感觉像是一个非常丑陋的黑客。

使用
@Configuration
不可能为每个方法定义多个bean(AFAIK)。因此,您必须继续使用BFPP或使用
ApplicationContect.getAutowireCapableBeanFactory().autowire(对象)

为了注入MyBean列表,请尝试@Resource而不是@Autowired。例如

@Resource
public List<MyBean> myBeans
@Resource
公共列表myBeans

我认为在这种情况下,另一种选择是以以下方式使用@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));
        }   
    }
}
@配置
公共配置{
@自动连线
私有配置配置;
listbeans=newarraylist();
@豆子
公共列表myBeans(){
返豆;
}
@施工后
公共void init(){
对于(设备:config.getDevices()){
添加(新的MyBean(设备));
}   
}
}
@PostConstruct注释对于初始化属性很有用。它保证在创建bean时只调用一次带注释的方法


如果我错了,请纠正我

mybean
没有经过后期处理,因为它们是使用
new
创建的,并且没有由Spring容器初始化

您需要使用原型bean,每个组件发出的请求都有一个新bean的实例

您需要标记
MyBean(设备)
bean声明,如

@Bean@Scope(ConfigurableBeanFactory.Scope\u原型)


然后调用它,而不是使用
new
来填充
bean

您可以使用
ConfigurableListableBeanFactory
,它支持
SmartLifecycle
,因此如果您在应用程序完全初始化之前注册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;
}
@Autowired
私有可配置列表beanFactory beanFactory;
@豆子
公共列表myBeansList(){
List mylist;//动态构建列表
while(myCondition){
蚕豆;
//使用Spring手动注册每个实例
registerSingleton(“此bean的唯一名称”,bean);
}
//将列表作为bean返回,这样您仍然可以自动关联bean列表
//但是每个bean已经被手动添加到上下文中
返回mylist;
}

我最终扩展了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());
        }
    }
}
@配置
公共类配置{
@自动连线
私有配置配置;
@豆子
公共列表myBeans(){
listbeans=newmybeanlist();
对于(最终设备:config.getDevices()){
添加(新的MyBean(设备));
}
返豆;
}
私有静态类MyBeanList扩展了ArrayList{
@施工后
公共void init(){
this.forEach(bean->bean.init());
}
@发情前期
公众假期结束(){
this.forEach(bean->bean.close());
}
}
}

当然,这有点骇人,但感觉没有提问者的方法那么难看。

谢谢,这将确保调用所有@Autowired方法。但是它没有向JMX注册bean并应用其他后处理。我还尝试了
ApplicationContect.getAutowireCapableBeanFactory().applyBeanPostProcessorsBeforeInitialization(bean,beanName)
ApplicationContect.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(bean,beanName)但由于没有bean定义,它们将不会执行完整的后处理。@这是有意义的,那么我猜您已经在尽可能最好地完成它了。对于这个不太常见的用例,仍然没有可接受的好答案吗?那太疯狂了。