- Issue
- when spring boot is boot, each beans are registred by sequentially. Normally spring boot load them each order by follow dependency injection.
- But sometimes injected bean is not loaded before, then spring boot can’t find target bean infromation.
- I met this situation at each bean are located in different projects.
- Example
- Engine project has refer to EngineCommon project.
- Engine project has MessageAdapter Bean, and EngineCommon project has NetworkInit bean.
- MessageAdapter bean is injected to NetworkInit bean.
- Engine project has bootRun.
- In this situation, Spring boot can’t find MessageAdapter bean when NetworkInit bean is loaded while Engine project boot.
- Reason
- Because MessageAdapter bean will be loaded after EngineCommon project’s bean are loaded first.
- Also @Order annotation is not work for setting ordering between them.
- Solution
- I make a BeanPostProcessor.
- Spring’s BeanPostProcessor gives us hooks into the Spring bean lifecycle to modify its configuration.
- BeanPostProcessor will be acted last step in loaded bean, and it can modify beans before regiser them to spring boot.
/** Engine Project **/
// MessageAdapt.java
// MessageAdapt
public class MessageAdapt{
}
// MessageAdaptConfiguration.java
// Bean configuration
@Configuration
public class MessageAdaptConfiguration {
@Bean
public MessageAdapt messageAdapt() {
return new MessageAdapt();
}
}
/** EngineCommon Project **/
// NetworkInit.java
// NetworkInit
public class NetworkInit{
private MessageAdapt messageAdapt
/**...omit...**/
public void setNetworkInit(MessageAdapt messageAdapt){
this.messageAdapt = messageAdapt;
}
/**...omit...**/
}
// NetworkInitConfiguration.java
// Bean configuration
@Configuration
public class NetwokInitConfiguration {
@Bean
public NetworkInit networkInit() {
return new NetworkInit();
}
/** Must BeanPostProcessor is registred by bean **/
@Bean
public NetworkInitBeanPostProcessor networkInitBeanPostProcessor() {
return new NetworkInitBeanPostProcessor();
}
}
//NetworkInitBeanPostProcessor.java
//
public class NetworkInitBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("networkInit")) {
MessageAdapt messageAdapt = applicationContext.getBean(MessageAdapt.class);
((NetworkInit) bean).setNetworkInit(messageAdapt);
}
return bean;
}
}
- Reference
- https://www.baeldung.com/spring-beanpostprocessor
- https://jaimemin.tistory.com/2028
- https://groups.google.com/g/gwt-sl/c/SDb3hd96MZg