Java – Creating a collection of beans in Spring using @Configuration

annotationscollectionsconfigurationjavaspring

How can I create a collection of beans that will be properly managed by Spring using a class with a @Configuration annotation.

I would like to do something like this:

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

But the MyBean instances aren't post processed. So their @Autowired methods are not called, the beans are not registered as mbeans and etc. The list is however accessible so that I can autowire a List of MyBean objects.

I cannot use something like:

@Configuration
public Config {
    @Autowired
    private SomeConfiguration config;

    @Bean
    public MyBean myBean1() { ... }

    @Bean
    public MyBean myBean2() { ... }
}

Since the number of MyBean instances are not known before runtime. The reason I want to do this is because we are controlling a physical machine that have a variable amount of components. And I want to have one bean per component.

I'm currently achieving our goal by using a BeanFactoryPostProcessor like this:

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

But this just feels like a really ugly hack.

Best Answer

In order to inject your MyBean list try @Resource instead of @Autowired. for e.g.

@Resource
public List<MyBean> myBeans