@Autowired自动注入怎么会空指针呢?

被@Component标识的类居然无法通过@Autowired注入,报的空指针!其实这个问题之前也有遇到过,在spring中也可以通过ApplicationContext的getBean方法获取指定bean,但还是想不通为什么会注入不进来,先说一下代码,大致这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Component
public class XXXUtil {
private final static Logger logger = LoggerFactory.getLogger(XXXUtil.class);

private final XXXDao xxxDao;

private List<DataProxy> proxyPool;

private Map<String, XXXClient> pool;

@Autowired
private XXXUtil(XXXDao xxxDao) {
this.xxxDao = xxxDao;
}

@PostConstruct
public void init() {
//...
}

public XXClient createClient(JobParam jobParam) {
XXClient xxClient;
//xxClient = ...
return webClient;
}
}

写了一个工具类,准备用在某Job中,但是是个子任务,顺序是在执行A任务中引用了B任务,而在B任务中利用@Autowired将XXXUtil注入使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@JobHandler(value = "AJob")
@Component
public class AJob extends AbstractJobHandlerWithBean {
@Override
void execute0(JobParam jobParam) throws Exception {
//...
BJob bJob = new BJob();
bJob.execute();
}
}

@JobHandler(value = "bJob")
@Component
public class BJob extends AbstractJobHandlerWithBean<ReportTaskParam> {
@Autowired
private XXXUtil xxxUtil;

//...
private String getReport(JobParam jobParam) {
XXClient xxClient =xxxUtil.createClient(jobParam);//这一行报空指针
}
}

这时BJob中就获取不到XXXUtil,空指针异常,其实不用打断点也知道,肯定是xxxUtil为null了,但因为BJob是个会被其他地方调用的类,如果写成了private final XXXUtil xxxUtil;,并放在构造函数里,对AJob来说无疑是多此一举,很没有必要。要解决这个问题必须得搞清楚为什么@Autowired在这注入不管用了,看到了这个博客才找到了问题所在,https://www.cnblogs.com/chyu/p/4655475.html,这里不得不吐槽bai度,还不如叫一度呢,查出来的解决不了问题不说还全是重复的,自从梯子坏了都没法谷歌,只能用bing勉强支撑。

文中写的很清楚,因为用构造函数直接new的BJob对象,是导致其中@Autowired失败的原因,回想一下一般性Service和Dao都是用@Autowired注入的,难怪这我直接用构造函数实例化一个bean会出问题,它也就是一个普普通通的Component啊,当然也应当有Component应有的亚子

至于为什么,这就要延申到Bean的生命周期了,所有的Spring的@Autowired注解都在构造函数之后,而成员变量毋庸置疑是最先进行的,所以三者的初始化顺序是,成员变量>构造函数>@Autowired,结合在这个问题上就是,① private final XXXUtil > ② new BJob() > ③ @Autowired private XXXUtil,弄懂了这个之后就豁然开朗了,由于构造函数的初始化方式是在@Autowired之前的,当我在调用BJob中的方法并试图取XXXUtil对象时,这个被@Autowired注入的可怜的对象还没有准备好

结论:@Component可以利用final变成成员变量或一律使用@Autowired的方式来引用