Vinicius Carvalho
Vinicius Carvalho

Reputation: 4146

Spring adding beans at runtime

I'm trying to come up with a way to add spring beans dynamically after an application has started.

I've found a couple of places with similar questions such as in here

And I'm aware of ApplicationContext extension points such as ApplicationContext events and BeanFactoryPostProcessor.

The issue I have at hand is that I need to add beans after some beans have been created, I guess that discards the BeanFactoryPostProcessor option, as it would happen before the application context starts registering beans.

I tried to add a singletonBean after the context was refreshed:

@EventListener
    public void postProcess(ContextRefreshedEvent refreshedEvent) throws BeansException {
        ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)refreshedEvent.getApplicationContext()).getBeanFactory();
        List<Api> apis = repository.findAll();
        apis.forEach(api -> {
            api.getEndpoints().forEach(endpoint -> {
                HttpRequestHandlingMessagingGateway gateway = createGateway(endpoint);
                customIntegrationHandlerMapping.register(gateway);
                beanFactory.registerSingleton("httpflow-"+endpoint.getId(),createEndpointFlow(gateway));
            });
        });
    }

The problem is that IntegrationFlow depends on a post processor that is not triggered after registering the singleton bean. I can't really force a refresh here.

Is there a way out of this chicken-egg problem?

Upvotes: 0

Views: 820

Answers (1)

Gary Russell
Gary Russell

Reputation: 174554

See AutowireCapableBeanFactory.initializeBean(beanName).

You need to make sure the bean's not used between registration and initialization.

Also, be aware that registering singletons after the context is initialized wasn't really thread-safe until recently (4.2.2, I think). It could cause ConcurrentModificationExceptions if other code is iterating over the beans in the factory.

However, in this case, it might be too late to get the HTTP paths registered, you might need more code to do that.

Upvotes: 2

Related Questions