无法在 HandlerInterceptorAdapter 中注入服务,获取 NullPointerException

Cannot Inject Service in HandlerInterceptorAdapter, Getting NullPointerException

我有一个服务客户端项目,它在正常的 spring 应用程序中,而不是 spring 启动。它主要用于与日志记录相关的 things.which 包含拦截器,loggingservice impl class 和一些用于日志记录的模型 classes。我已将此模块添加为 pom.xml 中主应用程序的依赖项。并且我能够在主应用程序的服务层中注入和使用 loggingService bean。

在拦截器中自动连接 loggingService 时得到 NullPointerException。bean 在 interceptor.but 中不可用,就像我说的那样,它可以在主应用程序中注入和使用。
我也无法在拦截器中使用 @Value 读取属性。

这是我的拦截器 class .

@Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    LoggingService loggingService;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        loggingService.info("Am in prehandle");
        return true;
    }
}

这是我的配置class,我在主应用程序中注册了拦截器

@Component
public class LoggingConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getLoginInterceptor());
    }

    @Bean
    public LoggingInterceptor getLoginInterceptor() {
        return new LoggingInterceptor();
    }

}

我的问题几乎与这个 post Cannot Autowire Service in HandlerInterceptorAdapter 相似,但它的不同之处在于我从另一个模块引用拦截器,就像他们建议的那样,我尝试从应用程序创建 bean。 但是现在面临的问题是

  1. 在拦截器中注入 loggingService 时得到 NullPointerException,但它在主应用程序中工作
  2. @Value 注释也 return 为 null,无法从属性中读取

您有 2 种可能的解决方案。

  1. 将您的 LoggingConfig 标记为 @Configuration 而不是 @Copmponent
  2. 注入 LoggingInterceptor 而不是引用 @Bean 方法

选项 1:LoggingConfig 作为 @Configuration

你的 LoggingConfig 被标记为 @Component 而它应该被标记为 @Configuration。不同之处在于,虽然允许在 @Component 上使用 @Bean 方法,但它在所谓的 lite mode 中运行。这意味着您不能使用方法引用来获取 bean 的实例(这是因为没有创建特殊的代理)。这将导致只创建 LoggingInterceptor 的一个新实例,但它不是一个 bean。

所以简而言之,您所做的等同于 registry.addInterceptor(new LoggingInterceptor()); 只是创建一个实例而 Spring 不知道它。

当将 LoggingConfig 标记为 @Configuration 时,将创建一个特殊的代理,这将使 LoggingInterceptor 成为一个合适的单例 bean,因为方法调用被拦截了。这将在 Spring 中注册 bean,您将能够调用该方法。

注意: 您实际上得到了 LoggingInterceptor 的 2 个实例,一个是由于 @Component,另一个是 @Bean .删除 @Component

选项 2:注入 LoggingInterceptor

因为您的 LoggingInterceptor 被标记为 @Component Spring 将已经创建一个实例(您实际上在当前设置中创建了 2 个实例)。您可以将此实例注入您的 LoggingConfig

@Component
public class LoggingConfig implements WebMvcConfigurer {

    private LoggingInterceptor loggingInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loggingInterceptor);
    }
}

有了这个,您可以删除 @Bean 方法,因为您将把正确的方法注入到您的 LoggingConfig class 中。在这种情况下,class 也可以保留为 @Component。虽然我建议使用 @Configuration 来正确地刻板印象。

注意: 如果您使用的是最新的 Spring 版本,您可以使用 @Configuration(proxyBeanMethods=false)。这将生成精简配置(就像 @Component),但它仍被正确标记为配置 class。