Spring源码:Bean生命周期(四)|当前热点
2023-05-15 18:27:06 来源:博客园
在之前的文章中,我们介绍了 Bean 的核心概念、Bean 定义的解析过程以及 Bean 创建的准备工作。在今天的文章中,我们将深入探讨 Bean 的创建过程,并主要讲解 createBean 方法的实现。在这个过程中,我们将了解 Bean 的实例化、属性注入、初始化和销毁等步骤,以及各个步骤的具体实现细节。通过本文的学习,读者将能够更深入地理解 Spring 框架中 Bean 的创建过程,从而为后续的学习和实践打下坚实的基础。好了,我们开始!
(相关资料图)
createBean前面我们说过,最开始的bean定义(合并后的),解析类的元数据时,用到的是ASM技术并不会真正开始解析class文件,所以也只是提取出来bean的name值作为beanClass属性,知道这个前提,那么这一步就好说了,下面是他的源码:
@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {RootBeanDefinition mbdToUse = mbd;// 马上就要实例化Bean了,确保beanClass被加载了Class> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.try {mbdToUse.prepareMethodOverrides();}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.// 实例化前Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}try {Object beanInstance = doCreateBean(beanName, mbdToUse, args);......return beanInstance;}}
resolveBeanClass:真正的开始加载bean。mbdToUse.prepareMethodOverrides();和@lookUp注解有关系,不看resolveBeforeInstantiation:实例化前的BeanPostProcessors,如果初始化了那么就返回了,不走其他创建逻辑了。doCreateBean:正常开始实例化、初始化bean。resolveBeanClass如果当前bean被加载了,那么直接返回了,如果没加载那么开始解析当前bean
@Nullableprotected Class> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class>... typesToMatch)throws CannotLoadBeanClassException {try {// 如果beanClass被加载了if (mbd.hasBeanClass()) {return mbd.getBeanClass();}// 如果beanClass没有被加载if (System.getSecurityManager() != null) {return AccessController.doPrivileged((PrivilegedExceptionAction>)() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());}else {return doResolveBeanClass(mbd, typesToMatch);}}}
是否已经加载的判断依据就是我说的,是否是class,正常下我们的beanClass为字符串,也就是beanname,看下源码:
public boolean hasBeanClass() {return (this.beanClass instanceof Class);}
doResolveBeanClass真正开始加载class,如果需要加载class那肯定离不开类加载器,看下源码:
@Nullableprivate Class> doResolveBeanClass(RootBeanDefinition mbd, Class>... typesToMatch)throws ClassNotFoundException {ClassLoader beanClassLoader = getBeanClassLoader();ClassLoader dynamicLoader = beanClassLoader;boolean freshResolve = false;if (!ObjectUtils.isEmpty(typesToMatch)) {// When just doing type checks (i.e. not creating an actual instance yet),// use the specified temporary class loader (e.g. in a weaving scenario).ClassLoader tempClassLoader = getTempClassLoader();if (tempClassLoader != null) {dynamicLoader = tempClassLoader;freshResolve = true;if (tempClassLoader instanceof DecoratingClassLoader) {DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;for (Class> typeToMatch : typesToMatch) {dcl.excludeClass(typeToMatch.getName());}}}}String className = mbd.getBeanClassName();if (className != null) {// 解析Spring表达式,有可能直接返回了一个Class对象Object evaluated = evaluateBeanDefinitionString(className, mbd);if (!className.equals(evaluated)) {// A dynamically resolved expression, supported as of 4.2...if (evaluated instanceof Class) {return (Class>) evaluated;}else if (evaluated instanceof String) {className = (String) evaluated;freshResolve = true;}else {throw new IllegalStateException("Invalid class name expression result: " + evaluated);}}if (freshResolve) {// When resolving against a temporary class loader, exit early in order// to avoid storing the resolved Class in the bean definition.if (dynamicLoader != null) {try {return dynamicLoader.loadClass(className);}catch (ClassNotFoundException ex) {if (logger.isTraceEnabled()) {logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);}}}return ClassUtils.forName(className, dynamicLoader);}}// Resolve regularly, caching the result in the BeanDefinition...return mbd.resolveBeanClass(beanClassLoader);}
我们自己的bean走不了这么多逻辑,我们既没有传typesToMatch,也没有写Spring表达式,所以就是拿了一个类加载器和使用类加载器加载class,如果我们没有自定义类加载器那么使用默认的,看下源码:
@Nullablepublic static ClassLoader getDefaultClassLoader() {ClassLoader cl = null;// 优先获取线程中的类加载器try {cl = Thread.currentThread().getContextClassLoader();}catch (Throwable ex) {// Cannot access thread context ClassLoader - falling back...}// 线程中类加载器为null的情况下,获取加载ClassUtils类的类加载器if (cl == null) {// No thread context class loader -> use class loader of this class.cl = ClassUtils.class.getClassLoader();if (cl == null) {// getClassLoader() returning null indicates the bootstrap ClassLoader// 加入ClassUtils是被Bootstrap类加载器加载的,则获取系统类加载器try {cl = ClassLoader.getSystemClassLoader();}catch (Throwable ex) {// Cannot access system ClassLoader - oh well, maybe the caller can live with null...}}}return cl;}
优先获取线程中的类加载器线程中类加载器为null的情况下,获取加载ClassUtils类的类加载器,这里Spring注意到了java的boostrap加载器,所以会有为null的情况如果为null,那么使用ClassUtils当前工具类使用的是哪个加载器假如ClassUtils是被Bootstrap类加载器加载的,则获取系统类加载器public Class> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {String className = getBeanClassName();if (className == null) {return null;}Class> resolvedClass = ClassUtils.forName(className, classLoader);this.beanClass = resolvedClass;return resolvedClass;}
public String getBeanClassName() {Object beanClassObject = this.beanClass;if (beanClassObject instanceof Class) {return ((Class>) beanClassObject).getName();}else {return (String) beanClassObject;}}
通过这一步也可以看出bean定义中最初的beanClass属性,都是String类型的beanname
resolveBeforeInstantiation这一步走的是实例化前的工作,当然如果你想在这一步中直接返回实体类也可,而且最离谱的是Spring并没有校验你返回的类是否是当前beanname的类,可以看下源码:
@Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.// synthetic表示合成,如果某些Bean式合成的,那么则不会经过BeanPostProcessor的处理if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class> targetType = determineTargetType(beanName, mbd);if (targetType != null) {bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}
hasInstantiationAwareBeanPostProcessors:直接从缓存list中获取有关实例化的BeanPostProcessors,这里是一个优化,要不然每次获取有关实例化的BeanPostProcessors都是遍历整个BeanPostProcessors再加个校验determineTargetType:获取类applyBeanPostProcessorsBeforeInstantiation:执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation的方法,该方法可以返回bean。postProcessAfterInstantiation:执行BeanPostProcessor的postProcessAfterInstantiation的方法,正常我们的bean不会走到这里,因为实例化前根本没有创建出来bean,所以也就是bean != null一直为false当然除非你自己写一个InstantiationAwareBeanPostProcessors,其实真没看见这么玩的,主要是没有啥意义,比如这样:
@Componentpublic class MyInstantiationAwareBeanPostProcessors implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {if (beanName.equals("userService")) {System.out.println("MyInstantiationAwareBeanPostProcessors.postProcessBeforeInstantiation");return new First();}return null;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("userService")) {System.out.println("MyInstantiationAwareBeanPostProcessors.postProcessAfterInitialization");return new Second();}return bean;}}
再坚持一下,让我把实例化过程先讲完!现在的逻辑已经走完了实例化前的postProcessBeforeInstantiation方法,那么现在我们的bean要进行实例化了,
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// 实例化bean// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 创建Bean实例instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 后置处理合并后的BeanDefinition// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// 为了解决循环依赖提前缓存单例创建工厂// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean "" + beanName +"" to allow for resolving potential circular references");}// 循环依赖-添加到三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// 属性填充populateBean(beanName, mbd, instanceWrapper); ......return exposedObject;}
跟这篇无关的内容能删除的都删除了,主要有这几步我们需要注意下:
createBeanInstance:创建实例,前提是之前没有创建过applyMergedBeanDefinitionPostProcessors:找到注入点,比如AutowiredAnnotationBeanPostProcessor(@Autowired、@Value、@Inject)和CommonAnnotationBeanPostProcessor(@Resource),这在实例化前和实例化后方法中间夹了一个处理合并bean定义的逻辑,注意一下addSingletonFactory:添加缓存,用来解决循环依赖,以后单独讲解populateBean:这一方法主要是属性填充也就是依赖注入的,但是官方把实例化后的PostProcessors方法写到这里了,所以也得贴出来,但是我们只看实例化相关的。createBeanInstanceprotected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.Class> beanClass = resolveBeanClass(mbd, beanName);if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn"t public, and non-public access not allowed: " + beanClass.getName());}// BeanDefinition中添加了Supplier,则调用Supplier来得到对象Supplier> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// @Bean对应的BeanDefinitionif (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);} ......return instantiateBean(beanName, mbd);}
resolveBeanClass:之前讲解过了,不重复讲了,就是拿到classobtainFromSupplier:通过Supplier函数获取bean,前提是你得声明bean定义instantiateUsingFactoryMethod:这种是使用@Bean方法实例化对象,后面省略了推断构造方法进行实例化对象,以后单独讲解推断构造方法obtainFromSupplier这一步其实我们用到的很少,主要是考虑到Spring自动注入的开销,我们自己可以就行实例化而已,比如我们这样写照样可以获取bean,但是不会由Spring帮我们注入,得靠自己了:
// 创建一个Spring容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(UserService.class);beanDefinition.setInstanceSupplier(() -> new UserService());applicationContext.registerBeanDefinition("userService", beanDefinition);UserService userService = (UserService) applicationContext.getBean(UserService.class);userService.test();
其实用法和@bean注解相似,除了减少Spring自动注入的开销,实在没想到有啥用
instantiateUsingFactoryMethod该方法内部逻辑很多,为了更加直观的展现,只贴出关键代码:
@Overridepublic Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,@Nullable Object factoryBean, final Method factoryMethod, Object... args) {try {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction
比如我们定义的配置类中有很多@Bean形式的方法,最终Spring会直接invoke调用被@Bean修饰的方法从而实现实例化对象。
applyMergedBeanDefinitionPostProcessors这里关于MergedBeanDefinitionPostProcessors的实现类不全讲解了,主要讲解下工作常用的注解AutowiredAnnotationBeanPostProcessor,他是用来解析@Autowired、@Value、@Inject,看下他的默认源码:
public AutowiredAnnotationBeanPostProcessor() {this.autowiredAnnotationTypes.add(Autowired.class);this.autowiredAnnotationTypes.add(Value.class);try {this.autowiredAnnotationTypes.add((Class extends Annotation>)ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));}}
看下他主要做了那些工作,关键代码附上:
private InjectionMetadata buildAutowiringMetadata(final Class> clazz) {// 如果一个Bean的类型是String...,那么则根本不需要进行依赖注入if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List elements = new ArrayList<>();Class> targetClass = clazz;do {final List currElements = new ArrayList<>();// 遍历targetClass中的所有FieldReflectionUtils.doWithLocalFields(targetClass, field -> {// field上是否存在@Autowired、@Value、@Inject中的其中一个MergedAnnotation> ann = findAutowiredAnnotation(field);if (ann != null) {// static filed不是注入点,不会进行自动注入if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static fields: " + field);}return;}// 构造注入点boolean required = determineRequiredStatus(ann);currElements.add(new AutowiredFieldElement(field, required));}});// 遍历targetClass中的所有MethodReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}// method上是否存在@Autowired、@Value、@Inject中的其中一个MergedAnnotation> ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {// static method不是注入点,不会进行自动注入if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static methods: " + method);}return;}// set方法最好有入参if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation should only be used on methods with parameters: " +method);}}boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}
如果一个Bean的类型是String,那么则根本不需要进行依赖注入遍历targetClass中的所有Field,是否存在@Autowired、@Value、@Inject中的其中一个,如果是static字段则不注入否则记录构造注入点遍历targetClass中的所有Method,是否存在@Autowired、@Value、@Inject中的其中一个,如果是static字段则不注入否则记录构造注入点populateBean这个方法主要是属性填充,也就是所说的依赖注入的过程,我们不讲解这一部分,只讲解关于实例化最后的阶段postProcessAfterInstantiation方法,方法进来第一步就是调用postProcessAfterInstantiation方法。但是只看Spring源码的话,其实并没有太多实现,都是默认实现方法:
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}
总结在本文中,我们深入探讨了 Spring 框架中 Bean 的实例化过程,关于某些细节以后我会单独拿出一篇文章单独讲解,我们来总结下实例化都做了哪些事情:
先从bean定义中加载当前类,因为最初Spring使用ASM技术解析元数据时只获取了当前类的名称寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化前的方法postProcessBeforeInstantiation进行实例化,这里会使用构造方法进行实例化调用applyMergedBeanDefinitionPostProcessors找到所有MergedBeanDefinitionPostProcessors的实现类,比如我们的注入点(@Autowired等)寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化后的方法postProcessAfterInstantiation通过本文的学习,读者将能够更深入地了解 Spring 框架中 Bean 的实例化过程,为后续的学习和实践打下坚实的基础。下一篇文章,我们将深入探讨 Bean 的初始化过程。
关键词:
为你推荐
-
Spring源码:Bean生命周期(四)|当前热点
-
5岁中法混血女孩惨遭父亲割喉身亡,事发前数小时法院曾向其父下达限制令
-
陈仓区气象台发布大风蓝色预警【Ⅳ级/一般】【2023-05-15】 热点聚焦
-
深度详解全新探歌,3款配置2套动力,哪一款更值得入手?
-
移民的想加入中国国籍怎么办_中国加入移民组织 环球视讯
-
环球头条:守护一江碧水的 “河湖卫士”
-
速读:p=fv适用于什么情况
-
荣国府和宁国府什么关系_荣国府与宁国府的关系结构
-
沃尔沃不做亏本生意,CEO 骆文襟:除非你真正拥有技术,否则永远无法完全理解_天天聚看点
-
二建建筑实务:钢结构安装质量控制 环球最资讯
-
美国从俄罗斯购买10亿美元浓缩铀 俄媒:俄产能占世界近一半 美别无选择
-
焦点快报!武警贵州总队新兵团训练如火如荼
-
奔向广阔市场 收获全球机遇|世界快播报
-
住友金属Ambatovy项目生产精炼镍同比增加12.36%
-
驻村更驻情!敢担当,善作为的引路人!
-
环球资讯:河南郑州新砦遗址或为夏代早期都城
-
沈阳:住房租赁企业收房租超3个月要存入监管账户
-
“衣织涨”会不会一直涨?|全球资讯
-
要闻速递:中光学:5月12日获融资买入534.14万元
-
美团红包在哪购买_美团红包在哪里购买|全球新消息
推荐内容
- Spring源码:Bean生命周期(四)|当前热点
- 5岁中法混血女孩惨遭父亲割喉身亡,事发前数小时
- 陈仓区气象台发布大风蓝色预警【Ⅳ级/一般】【202
- 深度详解全新探歌,3款配置2套动力,哪一款更值得
- 移民的想加入中国国籍怎么办_中国加入移民组织
- 环球头条:守护一江碧水的 “河湖卫士”
- 速读:p=fv适用于什么情况
- 荣国府和宁国府什么关系_荣国府与宁国府的关系结构
- 沃尔沃不做亏本生意,CEO 骆文襟:除非你真正拥
- 二建建筑实务:钢结构安装质量控制 环球最资讯
- 美国从俄罗斯购买10亿美元浓缩铀 俄媒:俄产能占
- 焦点快报!武警贵州总队新兵团训练如火如荼
- 奔向广阔市场 收获全球机遇|世界快播报
- 住友金属Ambatovy项目生产精炼镍同比增加12.36%
- 驻村更驻情!敢担当,善作为的引路人!
- 环球资讯:河南郑州新砦遗址或为夏代早期都城
- 沈阳:住房租赁企业收房租超3个月要存入监管账户
- “衣织涨”会不会一直涨?|全球资讯
- 要闻速递:中光学:5月12日获融资买入534.14万元
- 美团红包在哪购买_美团红包在哪里购买|全球新消息
- 4月经济数据公布,A股新股申购,解禁市值大减
- 商汤杨帆:大模型非暴力美学 天天热点
- 我女朋友的美女_我的性感女友
- 看热讯:宿州市哪个医院男科好
- 河南内乡花生“期货6+”助农创新模式研讨会在沪举
- 专访 | 两个世界第一!袁宏明详解陕汽重卡缘何
- 今日快看!广东欧珀移动通信有限公司 oppo_广东欧
- 筹备工作进入冲刺阶段 杭州亚运会测试赛五月起密
- 农家小葱炒蛋为什么颜色鲜艳?怎么做好吃?-环球报
- 大哥13 Ultra同款!小米13/Pro相机界面升级:变
- 韩国介绍派团赴日考察核污水排海:不只听日方说
- 世界播报:伊拉克宣布原油储量增加100亿桶
- 宁乡—韶山高速公路-新要闻
- 气温“狂飙”,京津冀等多地组团超35℃!
- 1-2!7轮6分,大连人的压着打失效,让谢晖执教申
- 快讯:浙江省科协到嘉善考察调研科技小院
- 每日热门:元敏诚庆祝胜利:单外援对抗四外援,我
- 盘点2023最值得期待的电摩,为何我给九号电动E300
- 如何戒掉游戏瘾 如何戒掉游戏瘾建议|每日报道
- 今日中心架一般用于车削不允许接刀的细长轴(加工
油气
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
经济
-
中新网通辽10月18日电 (记者 张林虎)18日,记者从内蒙古自治区通辽市奈曼旗公安局获悉,国家一级保护动物--梅花鹿误入当地村民羊群,
-
中新网杭州10月18日电 (王题题 胡燕婕)云天收夏色,浅秋正渐浓。10月18日,浙江杭州市西湖游船有限公司推出的惠民多站点“西湖环湖游
-
中新网福州10月18日电 (记者 龙敏 王东明)福州市晋安区官方18日晚间通报,18日14时47分,晋安区岳峰镇化工路爱摩轮商业广场项目摩天
-
中新网兰州10月18日电 (闫姣 艾庆龙 吉翔)“红山白土头,黄河向西流。”不少人疑问,天下黄河向东流,为何甘肃永靖县这段黄河却向西
-
中新网北京10月18日电 《清华城市健康设施指数》18日在北京发布。报告成果显示,城市健康设施指数领先城市以中心城市和东部沿海城市