Spring boot bean null exception

3.5k Views Asked by At
@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>
1

There are 1 best solutions below

2
On BEST ANSWER

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.