Spring - 使用带有@Autowired字段的@Service创建@Bean会导致@Autowired字段出现NullPointerException

时间:2017-11-14 09:11:05

标签: java spring testing

我有以下背景:

@Configuration
@ComponentScan
public class MyContext {

    @Bean
    public Logger getLogger() {
        return LoggerFactory.getLogger(MyContext.class);
    }

    @Bean
    @Autowired
    public RequestSpecification getRequestSpecification(RestServiceImpl restService) {
        return restService.getService();
    }
}

我的服务内部有@Autowired字段(Logger):

@Service
public class RestServiceImpl {

      @Autowired
      Logger logger;
}

现在问题来了。当我尝试在其他服务中重用我的RequestSpecification时:

@Service
public class RequestWrapperForMyEndpoint {
    @Value("${rest.service.url}")
    private String SERVICE_URL;

    @Autowired
    private RequestSpecification restService;
}

我遇到了NullPointerException。因为Logger没有注入RestServiceImpl类。

是什么原因?

2 个答案:

答案 0 :(得分:3)

我对你的具体问题的简单回答是:不要注射记录器。

@Service
public class RestServiceImpl {
      private static Logger logger = LoggerFactory.getLogger(RestServiceImpl.class);
}

参数#1:无论你在一个类中记录什么,都应该使用该类的记录器。您不应该使用从MyContext初始化的记录器在RestServiceImpl中进行日志记录。减少记录器的数量是没有意义的。每个类应该有一个记录器,它不会影响你的性能,因为创建记录器非常便宜。

参数#2:实例化记录器的价格并不像自动装配bean那么便宜。自动装配/并且可能在其间具有自动生成的代理bean非常昂贵。

论据#3:有人可能会说,自动装配一切都是好的设计。然后你仍然可以争辩 - 是的,除了不依赖任何东西的物体之外的一切。记录器就是其中一个例外。根据定义,它不依赖于其他任何东西。

抱歉 - 但我对您的实际自动装配问题没有任何好处。

答案 1 :(得分:0)

这可能是一个评论,但由于我没有足够的分数,我只能发表答案。我们走了:

因此,此代码应该有效,这就是应该如何进行自动装配。

虽然自动装配记录器没有意义(正如Mick所解释的那样),因为每个日志条目都将链接到MyContext,您将无法分辨它实际来自哪里(在调试时没有帮助),是可能的解决方案对于自动装配问题:

  1. 运行调试器并检查LoggerFactory.getLogger(MyContext.class)的返回值是否首先不为空。
  2. 仅在实际运行Spring应用程序并构建上下文时,自动装配才有效。它在单元测试中不起作用(如果发生的话)。对于测试,您需要运行集成测试。
  3. 检查代码中的其他位置是否覆盖了bean。
  4. 您没有显示您的restService.getService()方法的样子。有可能,这是您的自动装配记录器丢失的地方,因为您显然没有“保留”整个自动装配的restService bean。