4

Normally I'm adding my objects to spring context using @Bean definition:

@Autowired
private SpringBus bus;

//register a singleton
@Bean
public WebservicePort getPort() {
    //new port()
    //initialize
    //configure
    //return port;
}

But now I need deeper control of the process, especially I want to create the bean name dynamically under which the bean is registered.

I tried:

@Service
public class MyPortRegistrar implements BeanDefinitionRegistryPostProcessor {

        @Autowired
        private SpringBus bus;

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println(bus); //prints null

            //create and configure port with the SpringBus
            Port port = new WebservicePort(bus); // -> throws NullPointerException
            beanFactory.autowireBean(port);
            beanFactory.initializeBean(port, "myDynamicPortName");  
        }
}

But this throws an NPE as the autowired dependecies are not yet initialized here!

So, how can I add those beans programatically?

membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • your problem is still not clear.....can you please explain a little bit more:? – Abhinab Kanrar Dec 03 '14 at 08:16
  • What is not clear exactly? I want to manually register beans in the spring context, and create the bean name myself. The problem is when postProcessBeanFactory() is called, the `SpringBus` is still null, thus a NPE is thrown. Probably the `@Autowired` dependencies are not yet processed when this method is called. So I'm asking how I could else register beans myself after all autowired dependencies have been processed. – membersound Dec 03 '14 at 08:17

3 Answers3

4

You should put this before:

beanFactory.autowireBean(port);

But, if you want to initialize a bean, I think that you want to create a single instance (I'm saying this because in the example, you used the @Bean annotation):

beanFactory.initializeBean(port, "myDynamicPortName");  

instead of a singleton one:

beanFactory.registerSingleton("myDynamicPortName", port);
Michael
  • 3,308
  • 5
  • 24
  • 36
4

You should autowire the bean factory, and use a @PostConstruct to register your bean. That way, you guarantee that all dependencies has been injected (the bean factory is injected by the container, no setup is needed).

@Service
public class MyPortRegistrar {

    @Autowired
    private ConfigurableBeanFactory beanFactory;

    @Autowired
    private SpringBus bus;

    @PostConstruct
    public void createPort() {
        Port port = new WebservicePort(bus);
        beanFactory.registerSingleton("myDynamicPortName", port);
    }
}
Khalid
  • 2,212
  • 11
  • 12
1

An alternative to Khalid's answer (which I think requires some additional dependencies and configuration) is to implement the InitializingBean interface:

@Service
public class MyPortRegistrar implements InitializingBean {

    @Autowired
    private SpringBus bus;

    @Autowired
    private ConfigurableBeanFactory beanFactory;

    @Override
    public void afterPropertiesSet() throws Exception
        System.out.println(bus); //prints null

        //create and configure port with the SpringBus
        Port port = new WebservicePort(bus); // -> throws NullPointerException
        beanFactory.autowireBean(port);
        beanFactory.initializeBean(port, "myDynamicPortName");  
    }
}
Alan Hay
  • 22,665
  • 4
  • 56
  • 110
  • I tried this, but `cxt.getBean("myDynamicPortName")` does not find the bean, so probably it's not working this way. – membersound Dec 03 '14 at 08:52