Springboot 被@Component注解的类调用@Autowired注解的类的元素报空指针异常

一. Springboot 被@Component注解的类调用@Autowired注解的类的元素报空指针异常

报错内容如下:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.baidu.pingo.webserver.utils.QueueUtil]: Constructor threw exception; nested exception is java.lang.NullPointerException
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:154)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1147)
        ... 25 common frames omitted
Caused by: java.lang.NullPointerException: null
        at com.baidu.pingo.webserver.utils.QueueUtil.<init>(QueueUtil.java:70)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
        ... 27 common frames omitted

原因:Spring初始化顺序:
类变量(static变量)
static初始化块
类的成员变量
普通初始化块
构造函数
被@Autowired注解的类
被@PostConstruct注解的方法

如果一个成员变量里需要使用到被@Autowired注解的类的属性,在@Autowired依赖注入后再进行初始化,不然会报空指针异常。
解决: 加入@PostConstruct注解,在init()方法里完成初始化

@Autowired
private AppProperty appProperty;

private int initialCapacity;
private int maximumSize;
private int expireAfterWrite;

/**
 * 初始化操作
 */
@PostConstruct
public void init() {
    initialCapacity = appProperty.getInitialCapacity();
    maximumSize = appProperty.getMaximumSize();
    expireAfterWrite = appProperty.getExpireAfterWrite();
}

@PostConstruct是java5的时候引入的注解,指的是在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。
被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行

也就是加载顺序

服务器加载Servlet -> servlet 构造函数的加载 -> postConstruct ->init(init是在service 中的初始化方法. 创建service 时发生的事件.) ->Service->destory->predestory->服务器卸载serlvet

那么问题:spring中Constructor、@Autowired、@PostConstruct的顺序
Constructor >> @Autowired >> @PostConstruct

依赖注入的字面意思就可以知道,要将对象p注入到对象a,那么首先就必须得生成对象p与对象a,才能执行注入。所以,如果一个类A中有个成员变量p被@Autowired注解,那么@Autowired注入是发生在A的构造方法执行完之后的。

@PostConstruct应用场景:
如果想在生成对象时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。

关于@PostConstruct的原理详细解析,这篇写的很好。
PostConstrust原理解析
在Bean的创建完成后,要进行Bean的初始化操作。初始化过程会解析出@PostConstruct注解的方法,并反射调用该方法。从而,在启动的时候该方法被执行了。

二.Java类成员变量、普通成员变量、初始化块、构造方法的初始化和执行顺序

一个类中包含如下几类东西,他们前后是有顺序关系的

1.静态属性:static 开头定义的属性
2.静态方法块: static {} 圈起来的方法块
3.普通属性: 未带static定义的属性
4.普通方法块: {} 圈起来的方法块
5.构造函数: 类名相同的方法
6.方法: 普通方法

总结:包含父子类和接口类

普通类:
静态变量
静态代码块
普通变量
普通代码块
构造函数

继承的子类:
父类静态变量
父类静态代码块
子类静态变量
子类静态代码块
父类普通变量
父类普通代码块
父类构造函数
子类普通变量
子类普通代码块
子类构造函数

详情见Java类初始化顺序说明

你可能感兴趣的:(Java)