I'm using a configuration class that uses dynamic bean registration:
@Configuration
public class ConfigClass {
@Autowired
private GenericApplicationContext applicationContext;
@PostConstruct
private void init() {
System.out.println("init");
applicationContext.registerBean("exService", ExecutorService.class, () -> Executors.newFixedThreadPool(10), bd -> bd.setAutowireCandidate(true));
System.out.println("init done");
}
}
If I try to autowire the bean, application startup fails with error Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.
From the logs I can see that the init method on config class wasn't called before the error as the two system out statements were not printed out.
However, when I use applicationContext.getBean(ExecutorService.class)
it does work without any issues.
Anyway I can get the bean to Autowire?
I'm deliberately not using the @Bean
annotation because I need to register the beans dynamically based on certain conditions.
getBean. Return an instance, which may be shared or independent, of the specified bean. This method allows a Spring BeanFactory to be used as a replacement for the Singleton or Prototype design pattern.
When @Autowired doesn't work. There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.
The ApplicationContext comes with advanced features, including several that are geared towards enterprise applications, while the BeanFactory comes with only basic features. Therefore, it's generally recommended to use the ApplicationContext, and we should use BeanFactory only when memory consumption is critical.
2) byType autowiring mode It internally uses setter injection. In this case, it works fine because you have created an instance of B type. It doesn't matter that you have different bean name than reference name. But, if you have multiple bean of one type, it will not work and throw exception.
It could be because you are registering your bean in the middle of the context initialization phase. If your target bean initializes and auto-wires ExecutorService
before ConfigClass
@PostConstruct
is invoked there simply is no bean available.
You can try forcing the initialization order:
@Component
@DependsOn("configClass")
public class MyComponent
@Autowired
private ExecutorService executorService;
However it would be cleaner to register a bean definition using BeanFactoryPostProcessor
with BeanDefinitionBuilder
:
@Component
public class MyBeanRegistration implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) bf;
reg.registerBeanDefinition("exService",
BeanDefinitionBuilder
.rootBeanDefinition(ExecutorService.class)
.setFactoryMethod("newWorkStealingPool")
.getBeanDefinition());
}
}
You can do like this:
@Resource
@Lazy
private ExecutorService executorService;
It works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With