【问题标题】:Cannot Inject Service in HandlerInterceptorAdapter, Getting NullPointerException无法在 HandlerInterceptorAdapter 中注入服务,出现 NullPointerException
【发布时间】:2020-08-31 19:57:08
【问题描述】:

我有一个服务客户端项目,它在普通的 spring 应用程序中,而不是 spring boot 。它主要用于记录相关的事情。它包含 Interceptor 、 loggingservice impl 类和一些用于记录的模型类。我已将此模块添加为 pom.xml 中的主应用程序的依赖项。我能够在主应用程序的服务层中注入和使用 loggingService bean。

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

这是我的拦截器类。

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

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

@Component
public class LoggingConfig implements WebMvcConfigurer {

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

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

}

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

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

【问题讨论】:

  • @Component 更改为@Configuration

标签: java spring spring-boot interceptor


【解决方案1】:

您有 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 实例,一个是由于@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 类中。在这种情况下,该类也可以保持为@Component。虽然我建议使用@Configuration 来正确地刻板印象它。

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

【讨论】:

  • 感谢@M.Deinum,它成功了
猜你喜欢
  • 2012-05-12
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-22
  • 1970-01-01
  • 2013-08-03
相关资源
最近更新 更多