Spring 引导 bean 空异常

Spring boot bean null exception

@SpringBootApplication
public class DataProcessorApplication {
   public static void main(String[] args) throws UnknownHostException {
   SpringApplication app = new SpringApplication(DataProcessorApplication.class);
   app.run();
}

后处理器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
  }
}

我的服务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...");
  }
}

异常

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>

Spring 在下一个序列中初始化上下文:

首先,基于应用程序配置和自动检测类(@Component@Service等)bean定义将被创建并注册到BeanDefinitionRegistry.

之后 Spring 将自动检测在其 bean 定义中实现 BeanFactoryPostProcessor 的 bean,并在创建任何其他 bean 之前应用它们。由于您的 BeanRegistryPostProcessorBeanFactoryPostProcessor 的实现,它将应用于此步骤。

之后 Spring 将自动检测所有实现 BeanPostProcessor 接口的 bean,并将它们应用于随后创建的任何 bean。其中一个 bean 是 AutowiredAnnotationBeanPostProcessor,它处理 @Autoware 注释。这意味着您的服务将在此步骤中注入。

如您所见,您正尝试在将 DataConfigurationService bean 注入 BeanRegistryPostProcessor 之前使用它。为了解决这个问题,您可以在 BeanRegistryPostProcessor 中实现 ApplicationContextAware 接口,然后直接从应用程序上下文中获取服务实例:

@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;            
    }
}

有关所谓的容器扩展点的更多详细信息,您可以在 Spring documentation.

中找到