Spring bean中 Autowire注解的属性总是为空,谈Java类的初始化与spring bean的生命周期

Spring bean中 Autowire注解的属性总是为空,谈Java类的初始化与spring bean的生命周期

阅读引导

1、成人学习,由点破面。

2、乔布斯说 connecting the dots,对于程序开发来说,也是如此,通过遇到的问题把知识点串联起来。

3、为自己工作,为自己的系统工作,做自己的老板,形成正循环:打磨当前工作的核心关键能力——>高效能工作——>更多时间打磨自己的系统——>更高效能工作——>打磨下个层次工作的核心关键能力……

4、核心竞争力,是指你拥有的(独特的)知识经验组合,经过你思维逻辑的组织梳理,在实践中产生无可替代的价值。打造自己的TMS系统(T:专业技术;M:沟通管理、S:行业解决方案),利用复利效应,让系统为自己工作。

团队中一个同事遇到了一个问题,想要把bService注入到Aservice中去使用,为什么AService中的bService属性总是为空?

下面的代码,为了简单起见,都简化成无实际意义的例子

有一个发送消息的策略类BService:

@Service
public class BService implements SendMsgService{

	@Override
	public void sendMsg(String msg) {
		// TODO Auto-generated method stub
		
	}
}

另外,假设还有一个组装发送消息服务的发送类:

public class MsgPublisher {
	private SendMsgService service;
	public MsgPublisher(SendMsgService service) {
		this.service = service;
	}
	
	public void send(String msg) {
		service.sendMsg(msg);
	}
}

最终调用服务:

@Service
public class AService {
	
	@Autowired
	private SendMsgService bService;
	
	private MsgPublisher msgPublisher = new MsgPublisher(bService);
	
	public void send(String msg) {
		msgPublisher.send(msg);
	}

}

这段代码有什么问题,为什么在调用AService类的send方法的时候,总是抛出空指针异常?

跟踪进去后发现,bService这个属性一直为空。

1 初步排查

在找到我之前,开发同事找人帮他看了,也自己排除了语法。

首先,注解都没有问题,没有配置错。

其次,为了证明bean都已经加载,添加了许多打印语句,证明bService确实是加载到spring的容器中了。

也就是说,初步排除了语法或者API使用问题。

2 替换方式

为了启发他解决问题,直接让他使用了spring 的InitializingBean,在afterPropertiesSet方法中,对MsgPublisher进行初始化,变成这样,问题就解决了。

@Service
public class AService implements InitializingBean{
	
	@Autowired
	private SendMsgService bService;
	
	private MsgPublisher msgPublisher;
	
	public void send(String msg) {
		msgPublisher.send(msg);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		msgPublisher = new MsgPublisher(bService);
	}

}

那么,为什么换一种方式就可以了呢?

3 根本原因(spring的bean初始化管理,在Java初始化之后)

实际上,spring容器对于bean的加载管理,是在Java类本身的加载之后的。

也就是说,首先进行Java类的加载,先得要初始化,就会先把static的变量、代码块加载,然后就是类变量等,那么首先:

private MsgPublisher msgPublisher = new MsgPublisher(bService);

加载的时候,bService还是空。

而在Java类加载成功之后,spring容器采取扫描,去把类解析beandefination,解析成bean管理。

而在spring容器中,只有getBean的时候,才会去对依赖的注解进行注入。

所以此种方法永远获取不到bService的实例。

4 进阶

通过这个问题,实际上还可以继续深入,了解bean的初始化流程,生命周期到底是什么样子的。

就能把spring bean的生命周期和Java类的生命周期结合起来。

再继续向下深入,spring的容器核心,是怎么个初始化流程?对外暴露了哪一些某个生命周期阶段进行管理的接口?

例如InitializingBean,那么销毁的时候呢?

整个容器本身又对外提供了哪些钩子,可以让开发者进行扩展?

这种设计思想,对于自己设计框架有何帮助?

在阅读源码过程中,是不是可以看到PathResource类,还需要自己去采用Java原生IO类去读取文件么?

PathMatchingResourcePatternResolver类能做什么?对于properties的加载,还需要自己写吗?

问题——》Java类加载——》spring bean声明周期——》常用API——》spring IoC容器源码——》工具类——》设计思想。

Spring bean中 Autowire注解的属性总是为空,谈Java类的初始化与spring bean的生命周期_第1张图片

你可能感兴趣的:(spring,java,编程语言)