你曾读spring源码 “不知所云”、“绞尽脑汁”、“不知所措”嘛🤣🤣🤣
那这篇文章可能会对你有所帮助,小编尝试用简单、易懂的例子来模拟spring经典代码👉Spring Bean生命周期及扩展点,
让你能够**轻松的读懂Spring Bean的生命周期,更加深入的理解Spring。**
那好,下面小编将从如下几个步骤来介绍✍️✍️✍️
1》回顾Spring Bean相关知识点
1.1》什么是Bean
1.2》什么是 Spring Bean 的生命周期
1.3》 Spring Bean 的生命周期的扩展点
2》模拟 Spring Bean 生命周期及扩展点
2.1》 流程图
2.2》 代码功能介绍
2.3》 代码实现
2.3.1》 指定扫描路径
2.3.2》 扫描、生成classList
2.3.3》 bean定义、建立beanName映射关系、保存beanPostProcessor对象
2.3.4》 实例化bean、对象填充属性、执行award方法、BeanPostProcessor干预、初始化、放入单例池、获取bean
2.3.5》 业务类实现
2.3.6》 运行结果
3》总结
1 》回顾Spring Bean相关知识点
1. 1 》 什么是Bean
对于普通的 Java 对象,当 new 的时候创建对象,然后该对象就能够使用了。一旦该对象不再被使用,则由 Java 自动进行垃圾回收。
而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。
简而言之,bean 是由 Spring IoC 容器实例化、组装和管理的对象。
1.2 》 什么是 Spring Bean 的生命周期
•普通的Java对象生命周期:
实例化
该对象不再被使用时通过垃圾回收机制进行回收
•Spring Bean 的生命周期:
实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction
1.3 》 Spring Bean 的生命周期的扩展点
•Bean 自身的方法
实例化 -> 属性赋值 -> 初始化 -> 销毁
•容器级的方法(BeanPostProcessor 一系列接口)
主要是后处理器方法,比如InstantiationAwareBeanPostProcessor、BeanPostProcessor 接口方法。
这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中。
在 Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用。
•Bean 级生命周期方法
可以理解为 Bean 类直接实现接口的方法,比如 BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean、DisposableBean 等方法,这些方法只对当前 Bean 生效。
如上为Spring Bean知识的回顾👏👏👏,如果忘记了,没关系,让咱们在代码中寻找记忆。下面咱们开始模拟Spring Bean 生命周期。
2 》 模拟 Spring Bean 生命周期及扩展点
在看代码之前,首先,先给大家展示一下流程图、代码功能介绍,方便大家理解。
2.1 》 流程图
2.2 》 代码功能介绍
Application.java 启动类,实例化spring容器
AnnotationConfig.java 配置类,指定扫描路径
AnnotationApplicationContext.java 核心类,bean创建、获取
BeanDefinition.java BeanDefinition定义
SqBeanPostProcessor.java 后置处理器,初始化前后对bean进行干预
User.java 业务类,用户对象,用户信息设置
UserService.java 业务类,用户service,实现BeanNameAware、InitializingBean
spring注解模拟
Autowired.java
Component.java
Lazy.java
Scope.java
ComponentScan.java
spring接口模拟
BeanNameAware.java
BeanPostProcessor.java
InitializingBean.java
现在咱们开始看代码、看代码、看代码✌️✌️✌️
2.3》 代码实现
2.3.1》 AnnotationConfig.java 指定扫描路径
@ComponentScan("com.hz.spring.demo.service")
public class AnnotationConfig {
}
2.3.2 》 AnnotationApplicationContext.java 扫描、生成classList
•根据配置类config,获取扫描路径
•通过类加载器获取target class 路径
•扫描文件路径,加载类文件,放入classList中,为类操作做准备
public AnnotationApplicationContext(Class<AnnotationConfig> config) {
this.config = config;
try {
// 扫描
ComponentScan componentScan = config.getAnnotation(ComponentScan.class);
// com.hz.spring.demo.service
String path = componentScan.value();
path = path.replace(".", "/");
// 通过类加载器 获取target class 路径
ClassLoader classLoader = AnnotationApplicationContext.class.getClassLoader();
URL url = classLoader.getResource(path);
if (url != null) {
// 获取classList
File file = new File(url.getFile());
List<Class<?>> classList = this.scanAndGetClassList(classLoader, file);
// bean定义、建立beanName映射关系、保存beanPostProcessor对象
this.compBdMap(classList);
// 实例化。创建bean。放入单例池
// 核心、核心、核心
this.instanceBean();
}
} catch (Exception e) {
log.error("AnnotationApplicationContext error:", e);
}
}
扫描、加载class
private List<Class<?>> scanAndGetClassList(ClassLoader classLoader, File file) {
List<Class<?>> classList = Lists.newArrayList();
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
try {
String absolutePath = f.getAbsolutePath();
// Window target文件路径
// D:\company\comp\company-rest\target\test-classes\com\hz\spring2\service\User.class
// D:\company\comp\company-rest\target\test-classes\com\hz\spring2\service\UserService.class
// absolutePath = absolutePath.substring(absolutePath.indexOf("com\\"), absolutePath.indexOf(".class"));
// absolutePath = absolutePath.replace("\\", ".");
// Mac target文件路径
// /Users/huzhong5/hz/IdeaProjects/yb-claim/psc-invoicing/target/test-classes/com/hz/spring/demo/service/UserService.class
absolutePath = absolutePath.substring(absolutePath.indexOf("com/"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("/", ".");
// absolutePath: com.hz.spring.demo.service.UserService
Class<?> clazz = classLoader.loadClass(absolutePath);
classList.add(clazz);
} catch (Exception e) {
log.error("scanAndGetClassList error e:", e);
}
}
}
}
return classList;
}
2.3.3 》 bean定义、建立beanName映射关系、保存beanPostProcessor对象
•遍历classList
•创建BeanDefinition、BeanDefinition赋值属性、建立beanName与BeanDefinition映射关系
•保存beanPostProcessor对象
private void compBdMap(List<Class<?>> classList) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
for (Class<?> clazz : classList) {
// 遍历 @Component("") 类。设置bean属性
if (clazz.isAnnotationPresent(Component.class)) {
Component clazzAnnotation = clazz.getAnnotation(Component.class);
String beanName = clazzAnnotation.value();
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClass(clazz);
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
String scope = scopeAnnotation.value();
beanDefinition.setScope(scope);
} else {
// 默认单例
beanDefinition.setScope(SCOPE_SINGLETON);
}
// userService:beanDefinition
beanDefinitionMap.put(beanName, beanDefinition);
// 保存beanPostProcessor对象
// 通过反射获取对象
// clazz : SQYCBeanPostProcessor
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
beanPostProcessorList.add(instance);
}
}
}
}
遍历beanDefinitionMap,判断beanDefinition作用域
• 作用域为单例Bean,放入单例池
• 作用域为多例Bean,多次创建
private void instanceBean() {
Set<Map.Entry<String, BeanDefinition>> entries = beanDefinitionMap.entrySet();
for (Map.Entry<String, BeanDefinition> entry : entries) {
BeanDefinition beanDefinition1 = entry.getValue();
String beanName = entry.getKey();
if (SCOPE_SINGLETON.equals(beanDefinition1.getScope())) {
if (!singletonObjects.containsKey(beanName)) {
// create
Object instance = this.doCreateBean(beanName, beanDefinition1);
singletonObjects.put(beanName, instance);
}
} else {
this.doCreateBean(beanName, beanDefinition1);
}
}
}
2.3.4 》 实例化bean、对象填充属性、执行award 方法、BeanPostProcessor干预、初始化、放入单例池、获取bean
•实例化bean
•对象填充属性
•BeanNameAware 设置beanName
•BeanPostProcessor,初始化前后进行bean干预
•InitializingBean 初始化,设置属性
•bean创建完成,返回bean,放入单例池
private Object doCreateBean(String beanName, BeanDefinition beanDefinition1) {
// com.hz.spring.demo.service.UserService
Class<?> beanClass = beanDefinition1.getBeanClass();
try {
// 实例化bean
Object instance = beanClass.getConstructor().newInstance();
// 填充属性。为bean添加属性。如:userService 添加属性 user
// 解析Autowired注解的属性
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (declaredField.isAnnotationPresent(Autowired.class)) {
// user 他也是一个bean。执行从单例池获取就可以
// 根据beanName获取对象
Object bean = this.getBean(declaredField.getName());
declaredField.setAccessible(true);
// 将属性declaredField 赋值给 instance
declaredField.set(instance, bean);
}
}
// award.通过beanNameAward实现获取beanName
if (instance instanceof BeanNameAware) {
((BeanNameAware) instance).setBeanName(beanName);
}
// 初始化之前。BeanPostProcessor干预。应用场景:AOP 、属性注入、资源回收
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
}
// 初始化。在属性注入完成后调用。可以对属性进行一些改动
if (instance instanceof InitializingBean) {
try {
((InitializingBean) instance).afterPropertiesSet();
} catch (Exception e) {
log.error("doCreateBean InitializingBean error:", e);
}
}
// 初始化之后。BeanPostProcessor干预
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
}
return instance;
} catch (Exception e) {
log.error("doCreateBean error:", e);
}
return null;
}
•根据beanName获取bean
public Object getBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
String scope = beanDefinition.getScope();
if (SCOPE_SINGLETON.equals(scope)) {
Object bean = singletonObjects.get(beanName);
if (bean == null) {
bean = this.doCreateBean(beanName, beanDefinition);
}
return bean;
} else if (SCOPE_PROTOTYPE.equals(scope)) {
return this.doCreateBean(beanName, beanDefinition);
}
return null;
}
BeanPostProcessor实现类定义
@Component("sqBeanPostProcessor")
@Slf4j
public class SqBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
log.info("SqBeanPostProcessor {} 初始化之前", beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
log.info("SqBeanPostProcessor {} 初始化之后", beanName);
// 可以改变对象。很强大
return bean;
}
}
如上,bean创建流程就完成啦✌️✌️✌️
2.3.5 》 业务类实现
下面,咱们看看业务类怎样对Spring Bean 进行扩展,
UserService业务核心类定义,实现BeanNameAware、InitializingBean,对bean进行干预;
•test() 方法,获取用户属性、beanName
•setBeanName() 通过beanNameAward实现获取beanName
•afterPropertiesSet() 在属性注入完成后调用,可以对属性进行一些改动
@Component("userService")
@Scope(value = "singleton")
@Slf4j
public class UserService implements BeanNameAware, InitializingBean {
@Autowired
private User user;
/**
* 可以通过spring award回调方法实现
* beanName应用场景:
* spring + dubbo。dubbo暴露服务,单个服务的地址可能是beanName的名称组成
*/
private String beanName;
/**
* 所有属性填充后。获得
*/
private String userName;
public void test() {
log.info("UserService test() user.age:{},beanName:{},userName:{}", user.getAge(), beanName, userName);
}
/**
* BeanNameAward
*
* @param beanName
*/
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
log.info("UserService setBeanName() beanName:{}", beanName);
}
/**
* InitializingBean
* 所有属性填充后获得
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
this.userName = "w";
this.user.setAge("24");
log.info("UserService afterPropertiesSet() userName:{},age:{}", userName, user.getAge());
}
}
2.3.6 》 运行结果
Application.java 启动类,实例化spring容器,获取userService对象,调用test方法。
@Slf4j
public class Application {
public static void main(String[] args) {
AnnotationApplicationContext configWebApplicationContext = new AnnotationApplicationContext(AnnotationConfig.class);
UserService userService = (UserService) configWebApplicationContext.getBean("userService");
userService.test();
}
}
下面我们来运行下,结果如下:
17:41:39.466 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor sqBeanPostProcessor 初始化之前 17:41:39.471 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor sqBeanPostProcessor 初始化之后 17:41:39.471 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor user 初始化之前 17:41:39.472 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor user 初始化之后 17:41:39.474 [main] INFO com.hz.spring.demo.service.UserService - UserService setBeanName() beanName:userService 17:41:39.474 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor userService 初始化之前 17:41:39.474 [main] INFO com.hz.spring.demo.service.UserService - UserService afterPropertiesSet() userName:w,age:24 17:41:39.474 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor userService 初始化之后 17:41:39.474 [main] INFO com.hz.spring.demo.service.UserService - UserService test() user.age:24,beanName:userService,userName:w
3 》 总结
如上为Spring Bean生命周期及扩展点代码模拟, 希望对大家有所帮助。🤝🤝🤝
作者:京东保险 胡忠
来源:京东云开发者社区 转载请注明来源