Issue
@SpringBootApplication
public class DataProcessorApplication {
public static void main(String[] args) throws UnknownHostException {
SpringApplication app = new SpringApplication(DataProcessorApplication.class);
app.run();
}
PostProcessor class
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class BeanRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
private static final Logger LOG = LoggerFactory.getLogger(BeanRegistryPostProcessor.class);
@Autowired
private DataConfigurationService dataConfigurationService;
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory factory)
throws BeansException {
// we don't want to touch existing beans
}
@Override
public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry){
dataConfigurationService.something(); // service bean is null here
}
}
My Service class
@Service
public class DataConfigurationService implements ApplicationListener<ApplicationReadyEvent> {
private static final Logger LOG = LoggerFactory.getLogger(DataConfigurationService.class);
@Override
public void onApplicationEvent(final ApplicationReadyEvent e) {
LOG.debug("Loading active DataConfiguration instance...");
}
}
Exception
java.lang.NullPointerException: null
at dataprocessor.configmodels.processor.BeanRegistryPostProcessor.postProcessBeanDefinitionRegistry(BeanRegistryPostProcessor.java:40)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:685)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:523)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:736)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313)
at dataprocessor.DataProcessorApplication.main(DataProcessorApplication.java:47)
2017-01-07 12:42:47.802 WARN 8880 --- [ main] ationConfigEmbeddedWebApplicationContext : Exception thrown from LifecycleProcessor on context close
java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7a138fc5: startup date [Sat Jan 07 12:42:46 CET 2017]; root of context hierarchy
at org.springframework.context.support.AbstractApplicationContext.getLifecycleProcessor(AbstractApplicationContext.java:416)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1004)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:963)
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:793)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324)
at dataprocessor.DataProcessorApplication.main(DataProcessorApplication.java:47)
2017-01-07 12:42:47.803 ERROR 8880 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Destroy method on bean with name 'org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory' threw an exception
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7a138fc5: startup date [Sat Jan 07 12:42:46 CET 2017]; root of context hierarchy
at org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:403)
at org.springframework.context.support.ApplicationListenerDetector.postProcessBeforeDestruction(ApplicationListenerDetector.java:97)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:233)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:951)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:958)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1035)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1011)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:963)
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:793)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324)
at dataprocessor.DataProcessorApplication.main(DataProcessorApplication.java:47)
POM
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
Solution
Spring initializes context in next sequence:
First, based on application configuration and automatically detected classes(@Component
, @Service
etc) bean definitions will be created and registered in BeanDefinitionRegistry
.
After that Spring will auto-detect beans which implement BeanFactoryPostProcessor in their bean definitions and apply them before any other beans get created. Since your BeanRegistryPostProcessor
is implementation of BeanFactoryPostProcessor
it will be applied on this step.
After that Spring will auto-detect all beans which implement BeanPostProcessor interface and will apply them to any beans subsequently created. One of this beans is AutowiredAnnotationBeanPostProcessor
which processes @Autoware
annotation. That means your service will be injected on this step.
As you see you're trying to use DataConfigurationService
bean before it will be injected into BeanRegistryPostProcessor
. For solve this problem you can implement ApplicationContextAware
interface in BeanRegistryPostProcessor
and then get instance of service directly from application context:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class BeanRegistryPostProcessor
implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware{
private ApplicationContext applicationContext;
...
@Override
public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry){
DataConfigurationService service = applicationContext.getBean(DataConfigurationService.class);
service.something();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
More details about so called Container Extension Points you can find in Spring documentation.
Answered By - Ken Bekov