【问题标题】:Null pointer exception for autowired class method自动装配类方法的空指针异常
【发布时间】:2021-06-05 08:24:28
【问题描述】:

我是 Apache Camel 的新手,正在尝试构建一个 api。它有三个类。

A 类 - 用于读取 application.properties 文件,如下所示

@Configuration
@ConfigurationProperties(prefix="api")
public class A{

private String username;

public String getUsername(){
    return username
}

B 类 - 阿帕奇骆驼路线。

C 类 - 自动装配 A 类的 Bean 类。

@Component
public class b extends RouteBuilder{
    @Autowired
    ClassC customC;

    public void configure{
        from("direct:start")
            .bean(customC)
            .to("log:first-timer")
    }
}

@Component
class C{
    @Autowired
    ClassA config;

    String username=config.getUsername();
}

每当 IDE 执行 api 时,它都会在 String username=config.getUsername(); 行中抛出 Null 指针异常。我已验证 spring boot 能够加载 application.properties。

我不知道为什么调用自动装配类的方法会抛出空指针异常。

【问题讨论】:

  • 应该 @configuration 是带有 C 大写字母的“@Configuration”。我不确定它是否在发布时打错了,但除此之外一切似乎都是正确的。
  • 你尝试过构造函数注入吗?
  • @Ferry,我在 c 类中尝试了构造函数注入“private ClassA config; public ClassC(ClassA config){ this.config=config;} String username=config.getUsername();”但它没有用。我是否正确地进行了构造函数注入?
  • 在构造函数中分配用户名,它会工作。如果您使用 Spring 4 或更低版本,或者 Spring boot 1,则需要在构造函数中添加 @Autowired。顺便说一句,现场注入是一种不好的做法。

标签: java spring spring-boot apache-camel


【解决方案1】:

问题出在您的C 类中。

@Component
class C{
    @Autowired
    A config;

    String username = config.gtUsername();
}

Spring初始化时的顺序是这样的:

  1. 创建C的实例
    (致电new C()
    这个构造函数调用username = config.gtUsername() 并以NullPointerException 失败,因为config 仍然是null
  2. 处理@Autowired
    (初始化您的 config 属性)
    但当然它并没有走到这一步,因为异常已经在第 1 步中发生了。

您可以通过删除 username 的初始化来解决此问题 来自构造函数的属性,而是将其放入单独的方法中 (我们称它为init())并使用@PostConstruct 对其进行注释。 另见Spring PostConstruct and PreDestroy Annotations

@Component
class C{
    @Autowired
    A config;

    String username;
    
    @PostConstruct
    void init() {
        username = config.getUsername();
    }
}

那么Spring初始化时的顺序是这样的:

  1. 创建一个C 实例
    (致电new C()
  2. 处理@Autowired
    (这会初始化您的 config 属性)
  3. 调用@PostConstruct-annotated 方法。
    (这将使用已初始化的 config 属性初始化您的 username 属性)

解决问题的另一种更简单的方法是使用构造函数 注射(正如@Ferry 在他的评论中已经建议的那样):

而不是依赖隐式默认构造函数, 你提供了一个@Autowired-annotated 构造函数,它 可以采用A config 参数。 此外:通过这样做,您将不需要 A config 财产了。

@Component
class C{ 
    String username;

    @Autowired
    C(A config) {
        username = config.getUsername();
    }
}

那么Spring初始化时的顺序是这样的:

  1. 处理@Autowired
    (通过调用new C(config) 创建C 的实例,其中config 是先前在自动装配过程中创建的 A 实例)
    这将使用构造函数接收到的config 初始化您的username 属性。

【讨论】:

  • 此外,从Spring Framework 4.3 开始,如果类只定义了一个构造函数,则构造函数注入不再需要在构造函数上添加@Autowired 注释。
  • 感谢@Thomas 的详细解释。
猜你喜欢
  • 2017-12-27
  • 1970-01-01
  • 2017-11-20
  • 2014-10-07
  • 2017-10-22
  • 1970-01-01
  • 2012-02-21
  • 2015-11-16
  • 1970-01-01
相关资源
最近更新 更多