首页 > 编程语言 >3.0 Spring生命周期源码解析

3.0 Spring生命周期源码解析

时间:2022-10-11 17:02:04浏览次数:84  
标签:Spring beanName class Bean 源码 3.0 public BeanDefinition

Spring最核心的功能之一就是创建对象(IOC)

Bean的生命周期指:在spring中,一个Bean的生成和销毁的过程

1. 生成BeanDefinition

Spring启动先进行扫描,调用

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)

扫描路径,得到BeanDefinition的Set集合

1.1扫描的流程

  1. 首先,通过ResourcePatternResolver获得指定包路径下的所有 .class 文件(Spring源码中将 此文件包装成了Resource对象)
  2. 遍历每个Resource对象
  3. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中 MetadataReaderFactory具体的实现类为CachingMetadataReaderFactoryMetadataReader的具体实现类为SimpleMetadataReader
  4. 利用MetadataReader进行excludeFiltersincludeFilters,以及条件注解@Conditional的筛选 (条件注解并不能理解:某个类上是否存在@Conditional注解,如果存在则调用注解中所指定 的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)
  5. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition
  6. 再基于metadataReader判断是不是对应的类是不是接口或抽象类
  7. 如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入结果集

MetadataReader表示类的元数据读取器,主要包含了一个AnnotationMetadata,功能有:

  1. 获取类的名字
  2. 获取父类的名字
  3. 获取所实现的所有接口名
  4. 获取所有内部类的名字
  5. 判断是不是抽象类
  6. 判断是不是接口
  7. 判断是不是一个注解
  8. 获取拥有某个注解的方法集合
  9. 获取类上添加的所有注解信息
  10. 获取类上添加的所有注解类型集合

CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是 利用的ASM技术,并没有加载这个类到JVM。并且,最终得到的ScannedGenericBeanDefinition对 象,beanClass属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object, 它即可以存储类的名字,也可以存储class对象)

另外还可以通过直接定义BeanDefinition,或 解析spring.xml文件的,或者@Bean注解得到BeanDefinition对象。

1.2 合并BeanDefinition

Spring中支持父子BeanDefinition

// child是单例Bean
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>

// child就是原型Bean
// child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>

根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的 BeanDefinition。

1.3 加载类

根据合并之后的BeanDefinition对象加载对应的class文件,

AbstractAutowireCapableBeanFactory#createBean加载

Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

if (mbd.hasBeanClass()) {
	return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {
	return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ‐>
	doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}else {
	return doResolveBeanClass(mbd, typesToMatch);
}

public boolean hasBeanClass() {
	return (this.beanClass instanceof Class);
}

beanClass属性的类型是Class,那么就直接返回,如果不是,则会根据类名进行加载 (doResolveBeanClass方法所做的事情)

利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用 ClassUtils.getDefaultClassLoader()所返回的类加载器来加载

  1. 优先返回当前线程中的ClassLoader
  2. 线程中类加载器为null的情况下,返回ClassUtils类的类加载器
  3. 如果ClassUtils类的类加载器为空,那么则表示是Bootstrap类加载器加载的ClassUtils类,那么 则返回系统类加载器

1.4 实例化前

在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean 实例化之前做一些启动动作。这个扩展点叫 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()

@Component
public class CustomBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
		System.out.println("实例化之前");
		return new UserService();
		}
		return null;
	}
}

这个方法有返回值,如果像上述的实现则表示不需要spring 来实例化,并且后续spring依赖注入等步骤也不会进行,直接执行初始化后这一步了

1.5 实例化

根据Beandefinition创建对象

1.5.1 Supplier创建对象

首先会判断BeanDefinition中是否设置了Supplier,如果是则调用Supplier.get()得到对象

// 使用BeanDefinition对象来设置Supplier
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>() {
	@Override
	public Object get() {
		return new UserService();
	}
});
context.registerBeanDefinition("userService", beanDefinition);

1.5.2 工厂方法创建对象

接着会检查是否设置了factoryMethod

//设置factoryMethod有两种方式
// 方式一
<bean id="userService" class="com.zhouyu.service.UserService" factory‐method="createUserService" />
//对应得类方式
public class UserService {
	public static UserService createUserService() {
		System.out.println("执行createUserService()");
		UserService userService = new UserService();
		return userService;
	}
	public void test() {
		System.out.println("test");
	}
}

//方式二
<bean id="commonService" class="com.zhouyu.service.CommonService"/>
<bean id="userService1" factory‐bean="commonService" factory‐method="createUserService"
/>
//对应得类方式
public class CommonService {
	public UserService createUserService() {
		return new UserService();
	}
}

需要注意的是,我们通过@Bean所定义的BeanDefinition,是存在factoryMethodfactoryBean 的,也就是和上面的方式二非常类似,@Bean所注解的方法就是factoryMethod,AppConfig对象 就是factoryBean。如果@Bean所所注解的方法是static的,那么对应的就是方式一。

1.5.3 推断构造方法

在推断构造方法中除了选择构造方法和查找入参对象以外,还会判断是否在对应类中使用Lookup注解的方法,如果存在就会将该方法封装为lookupOverride对象添加到BeanDefinition

在实例化时如果没有LookupOverride对象会直接用构造方法反射生成实例对象,如果存在则生成一个代理对象

// @Lookup注解就是方法注入
@Component
public class UserService {
	private OrderService orderService;
	public void test() {
		OrderService orderService = createOrderService();
		System.out.println(orderService);
	}
	@Lookup("orderService")
	public OrderService createOrderService() {
		return null;
	}
}

1.6 BeanDefinition的后置处理

Bean对象实例化之后就该给对象赋值了,在赋值之前,spring有提供了一个扩展点,可以对BeanDefinition加工

MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()

@Component
public class CustomMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,Class<?> beanType, String beanName) {
		if ("userService".equals(beanName)) {
			beanDefinition.getPropertyValues().add("orderService", new OrderService());
		}
	}
}

应用:

在Spring源码中,AutowiredAnnotationBeanPostProcessor就是一个 MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()中会去查找注 入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中 (injectionMetadataCache

1.7 实例化后

在处理完BeanDefinition后,Spring又设计了一个扩展点,对所实例化出来的对象进行处理。InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()

@Component
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
			UserService userService = (UserService) bean;
			userService.test();
		}
		return true;
	}
}

1.8 自动注入

spring的自动注入,依赖注入部分详解

1.9 处理属性

这个步骤中,就会处理@Autowired、@Resource、@Value等注解,也是通过 InstantiationAwareBeanPostProcessor.postProcessProperties()扩展点来实现的,比如我们 甚至可以实现一个自己的自动注入功能,比如

// @CustomInject自定义注解标识的字段设置值
@Component
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
			for (Field field : bean.getClass().getFields()) {
				if (field.isAnnotationPresent(.class)) {
					field.setAccessible(true);
					try {
						field.set(bean, "123");
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}	
        }
		return pvs;
	}
}

1.10 执行Aware

完成了属性赋值之后,Spring会执行一些回调,包括:

  • BeanNameAware:回传beanName给bean对象。
  • BeanClassLoaderAware:回传classLoader给bean对象。
  • BeanFactoryAware:回传beanFactory给对象。

1.11 初始化前

初始化前,也是Spring提供的一个扩展点: BeanPostProcessor.postProcessBeforeInitialization()

  @Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    	if ("userService".equals(beanName)) {
        	System.out.println("初始化前");
        }
            return bean;
        }
}

利用初始化前,可以对进行了依赖注入的Bean进行处理

在Spring源码中:

  • InitDestroyAnnotationBeanPostProcessor会在初始化前这个步骤中执行@PostConstruct的 方法,
  • ApplicationContextAwareProcessor会在初始化前这个步骤中进行其他Aware的回调:
    • EnvironmentAware:回传环境变量
    • EmbeddedValueResolverAware:回传占位符解析器
    • ResourceLoaderAware:回传资源加载器
    • ApplicationEventPublisherAware:回传事件发布器
    • MessageSourceAware:回传国际化资源
    • ApplicationStartupAware:回传应用其他监听对象,可忽略
    • ApplicationContextAware:回传Spring容器ApplicationContext

1.12 初始化

  • 查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet() 方法
  • 执行BeanDefinition中指定的初始化方法

1.13 初始化后

这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点: BeanPostProcessor.postProcessAfterInitialization()

可以在这个步骤中,对Bean最终进行处理,Spring中的AOP就是基于初始化后实现的,初始化后返 回的对象才是最终的Bean对象。

public static void main(String[] args) {
        @Component
        public class CustomBeanPostProcessor implements BeanPostProcessor {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if ("userService".equals(beanName)) {
                    System.out.println("初始化后");
                }
                return bean;
            }
        }
    }

1.14 总结BeanPostProcessor

  • InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
  • 实例化
  • MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
  • InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
  • 自动注入
  • InstantiationAwareBeanPostProcessor.postProcessProperties()
  • Aware对象
  • BeanPostProcessor.postProcessBeforeInitialization()
  • 初始化
  • BeanPostProcessor.postProcessAfterInitialization()

2.Bean的销毁过程

Bean销毁是发生在Spring容器关闭过程中

AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
// 容器关闭
context.close();

在Bean创建过程中,在最后(初始化之后),有一个步骤会去判断当前创建的Bean是不是 DisposableBean

  1. 当前Bean是否实现了DisposableBean接口

  2. 或者,当前Bean是否实现了AutoCloseable接口

  3. BeanDefinition中是否指定了destroyMethod

  4. 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断

    • ApplicationListenerDetector中直接使得ApplicationListenerDisposableBean

    • InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是DisposableBean

  5. 把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入 disposableBeans中(一个LinkedHashMap)

在spring容器关闭时:

  1. 首先发布ContextClosedEvent事件

  2. 调用lifecycleProcessoronCloese()方法

  3. 销毁单例Bean

    • 遍历disposableBeans

      • 把每个disposableBean从单例池中移除

      • 调用disposableBeandestroy()

      • 如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean

      • 如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉

        (inner bean参考链接)

    • 清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的 beanName

    • 清空allBeanNamesByType,是一个Map,key是bean类型,value是该类型所有的 beanName数组

    • 清空singletonBeanNamesByType,和allBeanNamesByType类似,只不过只存了单例 Bean

这里涉及到一个设计模式:适配器模式

在销毁时,Spring会找出实现了DisposableBean的Bean,有上述几类情况。

这些Bean在容器关闭时都要调用相应的销毁方法。 所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter

会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter 实现了DisposableBean接口

标签:Spring,beanName,class,Bean,源码,3.0,public,BeanDefinition
From: https://www.cnblogs.com/ppku/p/16779781.html

相关文章

  • SpringBoot学习-(十九)SpringBoot定时器#Schedule
    定时器概述后台项目开发中经常会用到定时器,现在实现定时器的方式也是多种多样。下面列举几种常见的定时器实现方式:Quartz:Quartz的使用相当广泛,它是一个功能强大的调度器,当然......
  • Lua5.3源码解析
    2022-10-11,16点52 大概看了2个月不到的时间,坚持每天看lua设计与实现.pdf还有csdn上面lua的博客.然后自己debug研究.最后把细节加到注释里面.建议看这个项目时候......
  • SpringBoot学习-(十五)SpringBoot热部署
    热部署最重要的功能就是自动应用代码更改到最新的App上面去。原理是在发现代码有更改之后,重新启动应用,但是比速度比手动停止后再启动还要更快,更快指的不是节省出来的手工操......
  • 工厂方法在Spring源码中的运用
    我们都知道Spring中IOC是使用的工厂模式,但是对于实现细节就一知半解了,今天这篇文章就带大家解读Spring中是如何使用工厂模式的。在上篇文章中我们懂了什么是工厂模式,这篇文......
  • drf三大认证之频率类源码解析
    主要从SimpleRateThrottle的allow_request方法开始分析第一步1.查看SimpleRateThrottle的allow_requestifself.rateisNone:returnTrue#表示没......
  • java Spring Cloud 全环境 简明快速 精准 详解 视频课程 -专题视频课程
    Maven下SpringCloud全环境—10645人已学习课程介绍        本课程介绍SpringCloud+maven+Eureka+zuul+微服务+客户端+feign+hystrix+ribbon+config负载均衡......
  • 云转码源码|m3u8切片程序全开源
     什么是云转码? 云转码是完全在云中将视频文件转换为其他格式的过程。更具体地说,转码意味着从单个编码视频文件创建不同大小、分辨率和比特率的新文件。这种方法使广播......
  • 运行springboot是左下角没有services窗口解决方案
    结果成功:参考博文:http://t.zoukankan.com/sxdcgaq8080-p-14543088.html......
  • 工厂方法在Spring源码中的运用
    我们都知道Spring中IOC是使用的工厂模式,但是对于实现细节就一知半解了,今天这篇文章就带大家解读Spring中是如何使用工厂模式的。在上篇文章中我们懂了什么是工厂模式,这篇......
  • SpringBoot整合ssh
    背景:测试环境连接生产环境的数据库,无法本地调试环境: JDK8Maven:3.6.3Springboot:2.1.4jsch:0.1.55Jsch百度百科介绍:JSch是SSH2的一个纯Java实现。它允许你连......