简体   繁体   English

Spring-使用@Autowired字段基于@Service创建@Bean会导致@Autowired字段出现NullPointerException

[英]Spring - creating @Bean based on @Service with @Autowired field causes NullPointerException on @Autowired field

I have following Context: 我有以下上下文:

@Configuration
@ComponentScan
public class MyContext {

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

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

My inside my service I have @Autowired field (Logger): 我的服务内部有@Autowired字段(记录器):

@Service
public class RestServiceImpl {

      @Autowired
      Logger logger;
}

And now the problem comes. 现在问题来了。 When I am trying to reuse my RequestSpecification in other service: 当我尝试在其他服务中重用我的RequestSpecification时:

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

    @Autowired
    private RequestSpecification restService;
}

I am running into NullPointerException . 我正在NullPointerException Because Logger is not injected into RestServiceImpl class. 因为没有将Logger注入RestServiceImpl类。

What is the reason? 是什么原因?

My very simple answer to your specific problem would be: Do NOT inject a logger. 对于您的特定问题,我的简单回答是:不要注入记录器。

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

Argument #1: Whatever you log inside a class, should be done with a logger of that class. 论点#1:无论您在某个班级内登录过什么,都应该使用该班级的记录器来完成。 You should NOT log from within RestServiceImpl with a logger which was initialized from MyContext. 您不应使用从MyContext初始化的记录器从RestServiceImpl内进行记录。 There is no point in reducing the number of loggers. 减少记录器的数量是没有意义的。 There should be one logger per class and it would not affect your performance, since creating loggers is very cheap. 每个班级应该有一个记录器,这不会影响您的性能,因为创建记录器非常便宜。

Argument #2: What's not quite as cheap as instantiating a logger is autowiring a bean. 论据2:自动实例化一个Bean并不像实例化记录器那样便宜。 Autowiring / and maybe having an auto-generated proxy bean in between is quite expensive. 自动装配/可能在两者之间使用自动生成的代理bean非常昂贵。

Argument #3: One might argue that it is good design to autowire EVERYTHING. 论据3:有人可能会认为将所有东西都自动接线是一个好的设计。 Then you could still argue - YES, everything but objects which do not depend on anything else. 然后您仍然可以争辩-是的,除了对象之外的所有东西都不依赖其他任何东西。 And a logger is one of those exceptions. 记录器就是其中之一。 It does not depend on anything else by definition. 根据定义,它不依赖任何其他内容。

Sorry - but I don't have any good idea for your actual autowiring problem. 抱歉-对于您的实际自动接线问题,我没有任何好主意。

This would rather be a comment, but since I do not have enough points I only can post answers. 这宁愿是一条评论,但由于我的积分不足,所以只能发表答案。 Here we go: 开始了:

As such, this code should work, this is how autowiring should be done as such. 这样,此代码应该起作用,这就是应该如何自动装配的方式。

Although there is no point in autowiring loggers (as Mick explained), since every log entry will be linked to MyContext you won't be able to tell where it actually comes from (not helpful when debugging), ere are possible solutions for the autowiring issue: 尽管自动装配记录器没有任何意义(如Mick所述),但是由于每个日志条目都将链接到MyContext,因此您将无法分辨出它的真正来源(调试时无济于事),因此有可能实现自动装配问题:

  1. Run the debugger and check if the return value of LoggerFactory.getLogger(MyContext.class) is not null in the first place. 运行调试器,并首先检查LoggerFactory.getLogger(MyContext.class)的返回值是否不为null。
  2. Autowiring only works when the Spring application is actually run and the context is built. 仅当实际运行Spring应用程序并构建上下文时,自动装配才起作用。 Ergo it does not work in unit tests (if this is when it occurs). 因此,它在单元测试中不起作用(如果发生的话)。 For testing, you need to run integration tests. 对于测试,您需要运行集成测试。
  3. Check if the bean is not overwritten somewhere else in the code. 检查bean是否在代码中的其他地方未被覆盖。
  4. You did not show what your restService.getService() method looks like. 您没有显示restService.getService()方法的外观。 There is a chance, this is where your autowired logger gets lost, since you obviously are not "keeping" the entire autowired restService bean. 很有可能这是您自动连接的记录器丢失的地方,因为您显然没有“保留”整个自动连接的restService bean。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM