doGetBean源码分析
2022-01-12 17:37:29 4 举报
AI智能生成
doGetBean源码分析
作者其他创作
大纲/内容
1. 如果是工厂bean则去除bean工厂前缀
2. 判断 ./1 处理后的名称是否为别名,是的话查找出真实bean名称进行返回
1. 转化bean名称 String beanName = transformedBeanName(name);
如果单例bean存在singletonObjects缓存中,说明该bean已经构造好并初始化化完成了因为在#4.7.1.6.1节点才会往singletonObjects中添加初始化完成的bean
1. 通过bean名称从singletonObjects中取值 Object singletonObject = this.singletonObjects.get(beanName);
如果bean正在创建,说明这个bean正处于循环依赖状态。比如A->B且B->A在加载A前会将A添加到singletonsCurrentlyInCreation(#4.7.1.3)接着开始构造A(#4.7.1.4.5.3),构造完后进行注入依赖(#4.7.1.4.5.7)发现依赖了B,则会去加载B在完成B的构造后注入依赖的时候发现又依赖了A则又会去加载A这个时候就会在这一步出现当前bean A正在创建的情形,因为如果B没有依赖A的话在B初始化完成后A会完成剩下的依赖注入及初始化操作然后从singletonsCurrentlyInCreation中移除(#4.7.1.5)
2. 如果 ./1 中有取到值则返该值,没取到且bean但bean正在创建则继续 ./3 逻辑。否则返回null 正在创建的bean会存放在 singletonsCurrentlyInCreation 中
进入到这个地方的时候一开始earlySingletonObjects中应该是没有当前bean的因为要在 ../5 中才会添加到earlySingletonObjects
3. 从earlySingletonObjects中取值,有取到则返回该值,没取到但allowEarlyReference为true则继续 ./4 逻辑。否则返回null singletonObject = this.earlySingletonObjects.get(beanName);
这个地方的singletonFactory是在(#4.7.1.4.5.5)中进行设置进去的,是解决循环依赖的关键在B加载A的时候进入到这个地方能取到singletonFactory的值,然后在 ../5 中调用 singletonFactory.getObject()返回未初始化完成的bean A 设置到B的依赖中,不会继续去创建A,这样就解决了循环依赖
4. 通过bean名称从singletonFactories中去获取ObjectFactory,如果没有取到则返回null,有则继续 ./5 逻辑 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
singletonObject = singletonFactory.getObject();
this.singletonFactories.remove(beanName);
5. 如果上一步得到的singletonFactory不为null,则执行右侧操作 singletonFactory
2. 通过 ./1 中转换的bean名称先尝试从单例缓存中取值 Object sharedInstance = getSingleton(beanName);
bean实例是NullBean则直接返回bean实例
bean实例不是工厂bean则抛出BeanIsNotAFactoryException异常
1. 如果name是以工厂bean前缀开头,先排除掉如右两种情况
2. bean实例不是个工厂bean或是个工厂bean且name还是以工厂bean前缀开头(说明是取bean工厂实例本身)则直接返回bean实例
3. 能走到这里则说明bean实例是个工厂bean,而且不是以工厂bean前缀开头说明不是想取工厂bean实例本身 则通过工厂bean实例获取getObject方法返回值进行返回
3. 如果 ./2 中sharedInstance有取到值且args参数为空,则调用getObjectForBeanInstance方法取出实例,在 ./6 处返回,否则进入 ./4 的处理逻辑 因为sharedInstance可能是个工厂bean,所以要做这个操作。需要注意的是传入的name是未经过 ./1 转换的namefont color=\"#0076b3\
1. 如果该beanName是正在创建的原型bean,则抛出BeanCurrentlyInCreationException异常 原型bean是不允许循环引用的,因为每次都需要创建新的实例,构造完后不能先放入缓存中
2. 如果存在父BeanFactory容器,且该beanName已经被父容器实例化过了则直接返回实例化好了的bean实例
1. 移除beanName在mergedBeanDefinitions集合中存在的值,让 ../4 中重写去执行合并操作 以防止上一次合并后bean定义数据发生了变化的情况
2. 将beanName添加到 Set<String> alreadyCreated集合中
3. 如果typeCheckOnly值为false说明是创建bean,而不是类型检查 markBeanAsCreated(beanName);
4. 如果beanName对应的bean定义不是RootBeanDefinition类型则会合并为RootBeanDefinition类型 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
5. 检查 mdb 是不是抽象类,是抽象类则抛出BeanIsAbstractException异常font color=\"#0076b3\
1. 取出 mdb @dependsOn注解中依赖的bean 名称数组 String[] dependsOn = mbd.getDependsOn();
3. 通过依赖缓存(下一步会添加)判断是否有循环依赖的情况,有则抛出BeanCreationException异常
1. 取出依赖bean的真实名称,防止依赖bean名称是个别名的情况 需要注意的是此处的beanName是 ../4 中传入的dep参数噢 String canonicalName = canonicalName(beanName);
2. 如果canonicalName在dependentBeanMap缓存中不存在则实例化一个LinkedHashSet 然后将dependentBeanName( ../4 中传入的beanName) 添加到set中 最后以canonicalName为key,set为值添加到dependentBeanMap缓存中缓存中 如果canonicalName之前就存在于缓存中,则把dependentBeanName 添加到对应的set中
3. 和上一步相似,只不过是以dependentBeanName作为key,canonicalName为set值添加到dependenciesForBeanMap缓存中
4. 注册依赖bean名称到依赖缓存中,上一步就是通过缓存判断是否有循环依赖的情况 font color=\"#0076b3\
5. 通过依赖bean 名称执行getBean操作 getBean(dep);
2. 如果上一步取出的dependsOn数组不为空则循环处理依赖bean
6. 如果 mdb 有@dependsOn注解依赖其他bean,则先处理依赖
1. 先尝试从singletonObjects缓存中获取,如果缓存中有值则直接返回,不进行后面的操作 Object singletonObject = this.singletonObjects.get(beanName);
2. 如果单例工厂正在在销毁,则抛出BeanCreationNotAllowedException异常
3. 创建单例bean之前的回调操作,主要操作是将beanName添加到singletonsCurrentlyInCreation缓存中 beforeSingletonCreation(beanName);
1. 将 mbd(#4.4中合并的RootBeanDefinition) 放入一个mbdToUse 变量中 RootBeanDefinition mbdToUse = mbd;
2. 如果mbd中的beanClass还未加载,则将beanClass加载后重新对mbdToUse赋值 font color=\"#0076b3\
3. 处理lookup-method 和 replace-method mbdToUse.prepareMethodOverrides();
1. 循环执行InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法 如果某个处理器有返回值则停止循环,将该值返回供下一步操作,若都没值返回则返回null
2. 上一步如果有值返回,则循环调用BeanPostProcessor#postProcessAfterInitialization方法 如果某个处理器返回null,则停止循环,返回当前值给 ../4
BeanPostProcessor类关系图
4. 执行实例化前的后置处理操作,如果能取到值,则直接返回 font color=\"#0076b3\
1. 定义一个BeanWrapper对象用来包装创建的bean对象 BeanWrapper instanceWrapper = null;
2. 如果是创建单例bean则先尝试通过beanName去factoryBeanInstanceCache缓存中取值赋值给instanceWrapper instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
1. 取出bean定义中的 beanClass,如果beanClass还没有加载会先加载class font color=\"#0076b3\
2. 如果beanClass不为null且不是public访问级别且nonPublicAccessAllowed为false 则抛出BeanCreationException异常
3. 如果存在supplier回调,则通过给定的回调方法初始化策略实例化返回 在使用GenericApplicationContext#registerBean方法注册bean时可以使用该方式font color=\"#0076b3\
4. 如果存在工厂方法,则通过工厂方法初始化返回 在方法上使用@Bean注解定义bean会使用该方式 font color=\"#0076b3\
5. 如果args为null且mdb.resolvedConstructorOrFactoryMethod不为null 则说明之前有解析过可使用缓存的构造器进行构建,不需要进入下一步的构造器选择
会循环调用SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors方法如果某个处理器有返回构造器则停止循环,将值放回给 ../6此处主要逻辑由AutowiredAnnotationBeanPostProcessor处理器处理
6. 根据参数确定候选构造器font color=\"#0076b3\
这一步中如果出现构造器注入参数循环依赖会抛出UnsatisfiedDependencyException构造器是不允许循环依赖的
7. 如果上一步有根据参数解析到匹配的构造器或者args参数不为null 或mdb.constructorArgumentValues不为空或mdb.autowireMode为自动注入模式 则使用自动注入构造方式进行实例化beanfont color=\"#0076b3\
8. 如果mdb中有设置默认的首选构造器 ctors = mbd.getPreferredConstructors();
9. 如果上一步判断不符合自动注入构造方式的条件,则使用默认的无参构造实例化bean font color=\"#0076b3\
3. 如果 ./2 中没取到值则创建wrapper对象赋值给instanceWrapper,真正的bean实例化在这一步 font color=\"#0076b3\
查找标注了@Resource注解的属性或方法,在 ../../7.5 中会进行依赖注入
查找标注了@PostConstruct注解的方法,在 ../../8.2 中会执行该方法会将该方法名称放入bean定义的externallyManagedInitMethods列表中
查找标注了@PreDestroy注解的方法会将该方法名称放入bean定义的externallyManagedDestroyMethods列表中
此处CommonAnnotationBeanPostProcessor会查找bean中标注了右侧注解的属性/方法放入injectionMetadataCache中,key为bean名称
此处AutowiredAnnotationBeanPostProcessor会获取bean中标有@Autowired注解的属性/方法放入injectionMetadataCache中供 ../7.5 进行使用,key为bean名称
4. 循环执行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法 类型的后置处理器,主要是用来缓存一些meta信息供后续属性填充用font color=\"#0076b3\
详情代码可查看aop(Aspectj)源码分析#4.2
需要注意的是此处添加单例bean工厂一个lambda表达式,在存在循环依赖时#2.5处会调用工厂的getObject就会执行该lambda表达式,该表达式中会循环SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法,如果该bean的某个方法满足代理条件则就会对这个该bean进行代理,这样依赖该对象就是依赖的代理类了
1. 往singletonFactories中添加beanName的单例工厂
2. 移除earlySingletonObjects中的beanName
3. 往registeredSingletons中添加beanName
5. 如果是单例bean且允许循环引用且当前bean正在创建中,则执行添加单例工厂的操作font color=\"#0076b3\
6. 定义一个exposedObject对象用于存在暴露的bean实例,后面可能会代理类覆盖 而instanceWrapper中依旧保存原始bean(存在earlySingletonObjects中的是原始bean) Object exposedObject = bean;
1. 对传入BeanWrapper做非空判断,如果为null则直接return 如果为空且有propertyValues值则抛出BeanCreationException异常
2. 循环执行InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation 如果其中某个控制器方法返回false,则会跳出循环且return方法不进行后面的操作了 此处也是在注入前最后一次能修改bean属性的时机,因为后面就要开始注入属性依赖了
3. 取出mbd中的propertyValues值 \t\tPropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
4. 判断依赖注入的方式,默认是0手动依赖(比如手动通过@Autowired注解标注属性的) AUTOWIRE_BY_NAME表示通过属性名进行自动依赖,AUTOWIRE_BY_TYPE表示根据属性类型进行自动依赖
1. CommonAnnotationBeanPostProcessor 对java中依赖注解进行处理,如:@Resource
2. AutowiredAnnotationBeanPostProcessor(会进入AutowiredAnnotationBeanPostProcessor#inject方法进行依赖注入) 对spring中的依赖注解进行处理:如:@Autowire 对@Value 标注的属性进行赋值(详细使用见备注)
5. 循环执行InstantiationAwareBeanPostProcessor#postProcessProperties方法 如果某个控制器返回null则return方法不进行后面的操作了 此处通过右侧两个控制器实现了bean属性的依赖注入
7. 对bean属性依赖进行填充,属性又依赖其他bean,则递归初始化其他bean font color=\"#0076b3\
在高版本的spring中@Resource和@Autowire功能差不多在依赖为非数组、容器类型存在多个实现bean时会通过@Primary、@Priority、属性名称进行匹配如果依赖为数组,容器(如:List<UserService> userServiceList)则会将所有的实现bean装入容器中
1. 如果实现了BeanNameAware或BeanClassLoaderAware或BeanFactoryAware接口则进行织入操作 font color=\"#0076b3\
如果bean中有标注@PostConstruct注解的方法,CommonAnnotationBeanPostProcessor处理器将执通过反射执行该方法
ImportAware使用示例
如果bean实现了ImportAware接口则ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor会在此时调用setImportMetadata方法
ApplicationContextAware
MessageSourceAware
ApplicationEventPublisherAware
ResourceLoaderAware
EmbeddedValueResolverAware
EnvironmentAware
如果bean实现右侧Aware接口,则ApplicationContextAwareProcessor处理器将在这一步进行织入操作
2. 循环执行BeanPostProcessor#postProcessBeforeInitialization方法 如果某个控制器返回null则return上一个处理器返回的值,不执行后面的处理器了font color=\"#0076b3\
1. 如果该bean实现了InitializingBean接口,且没有被@PostConstruct注解标注且方法名为afterPropertiesSet的方法则执行InitializingBean#afterPropertiesSet方法
1. 该bean没有实现InitializingBean接口或实现了该接口但initMethodName值不为afterPropertiesSet
2. 没有被@PostConstruct注解标注且方法名为initMethodName的方法
2. 如果该bean定义中有设置initMethodName值,且满足右侧两个条件 则通过反射执行该initMethodName方法
3. 执行afterPropertiesSet和initMethod方法 font color=\"#0076b3\
如果bean实现了ApplicationListener接口ApplicationListenerDetector将在这一步将该监听器添加到ApplicationContext#applicationEventMulticaster中
aop(Aspectj)源码分析
4. 循环执行BeanPostProcessor#postProcessAfterInitialization方法 如果某个控制器返回null则return上一个处理器返回的值,不执行后面的处理器了 aop代理通常就是在这个地方进行的,详情可查看aop(Aspectj)源码分析#4.3 font color=\"#0076b3\
8. 对bean进行初始化 font color=\"#0076b3\
当前bean中使用了@Async注解会可能会出现不相等的情况,因为@Async注解是在initializeBean的时候(#4.7.1.4.5.8)进行代理bean的,而去加载依赖是在initializeBean(#4.7.1.4.5.7),比代理的时间早,所以会导致依赖的是原始bean,而暴露的是代理bean在循环依赖时不会有这种问题,因为循环依赖时依赖的bean在4.7.1.4.5.5.1就进行了代理,所以不会有这种问题解决方案可在依赖该bean的时候添加@Lazy注解@Lazy实现原理:AutowiredAnnotationBeanPostProcessor#postProcessProperties方法在加载属性依赖的时候如果发现有标注@Lazy注解则会为依赖的添加代理,在真正调用依赖的时候才会从bean容器中重新加载bean对象再通过反射调用bean对象的方法,这样就起到了延迟加载的效果具体代理代码可查看ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy方法
2. 暴露的exposedObject和原始bean相同则earlySingletonReference赋值给exposedObject exposedObject = earlySingletonReference;
4. 取出所有的依赖bean名称
5. 循环上面的依赖bean,如果有一个bean是存在alreadyCreated中(加载完毕,不会加载依赖了) 则抛出BeanCurrentlyInCreationException异常
3. 上一步的条件不满足且allowRawInjectionDespiteWrapping=false 且有依赖bean则进入该处理逻辑
1. getSingleton方法获取earlySingletonReference(如果循环依赖的话是有值的)font color=\"#0076b3\
9. 处理循环依赖有时原始bean和暴露bean不一致的情况
10. 注册bean销毁时的回调(@PreDestroy/DisposableBean/destroy-method)
5. 执行创建bean逻辑 font color=\"#0076b3\
4. 执行 ../1 中传入的 createBean 操作 singletonObject = singletonFactory.getObject();
5. 创建完单例bean的回调,主要操作是将beanName从singletonsCurrentlyInCreation缓存中移除 afterSingletonCreation(beanName);
1. 将创建好的单例bean添加到singletonObjects缓存中 font color=\"#0076b3\
2. 将beanName从singletonFactories缓存中移除 this.singletonFactories.remove(beanName);
3. 将beanName从earlySingletonObjects缓存中移除 this.earlySingletonObjects.remove(beanName);
4. 将beanName添加到registeredSingletons缓存中 this.registeredSingletons.add(beanName);
6. 将创建好的单例bean添加到缓存中font color=\"#0076b3\
2. 通过上一步获取的实例进行getObjectForBeanInstance,和#3中一样的操作 font color=\"#0076b3\
7. 如果mdb 是单例bean,执行单例bean实例化逻辑,否则进入下一步
1. 如果prototypesCurrentlyInCreation中没有值则直接把当前bean名称放入prototypesCurrentlyInCreation中
2. 如果prototypesCurrentlyInCreation中有值且为String则说明是在加载依赖bean 则把prototypesCurrentlyInCreation中已经存在的bean名称和正在加载的bean名称添加到一个Set集合中 然后将该Set集合放入prototypesCurrentlyInCreation中
3. 如果不符合 ./1 和 ./2 则说明prototypesCurrentlyInCreation中已经是个Set集合了 则将当前加载的bean名称添加到Set集合中就行了
1. 将当前正在创建的原型bean名称添加到prototypesCurrentlyInCreation中 因为是原型bean,所以prototypesCurrentlyInCreation为ThreadLocal类型 beforePrototypeCreation(beanName);
2. 执行创建bean的操作,参考 #4.7.1.4 font color=\"#0076b3\
3. 进行 ./1 中添加到prototypesCurrentlyInCreation中的bean名称进行移除操作 afterPrototypeCreation(beanName);
4. 通过上一步获取的实例进行getObjectForBeanInstance,和#3中一样的操作 font color=\"#0076b3\
8. 如果mdb 是原型bean,执行原型bean实例化逻辑,否则进入下一步
1. 取出当前bean定义中的scope值 String scopeName = mbd.getScope();
在springboot内嵌初始化#2.7.4.1.3有对BeanFactory#scope进行设置request值为RequestScope继承自AbstractRequestAttributesScope,在该抽象父类中实现了获取bean实例的get方法session值为SessionScope继承自AbstractRequestAttributesScope,重写了父类的get方法(会先进行加锁操作然后调用父类的get方法)
2. 通过scopeName从BeanFactory#scope中取出Scope对象 如果没有取到则抛出IllegalStateException异常 final Scope scope = this.scopes.get(scopeName);
1. 取出当前请求的RequestAttributesRequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
2. 根据作用域去不同的地方通过bean名称尝试去取bean实例,如去request或session中取 font color=\"#0076b3\
3. 上一步在对应的作用域中有获取到值则直接放回,没有的话则通过通过传入的ObjectFactory#getObject方法进行获取bean实例 然后通过将获取到的bean实例设置到对应的作用域中 scopedObject = objectFactory.getObject();font color=\"#0076b3\
3. 通过上一步取出的scope#get方法获取bean实例,第二个参数为ObjectFactory 此处传入的是个lambda表达式,该表达式里面的获取bean实例逻辑和#4.8一样 font color=\"#0076b3\
9. 执行mdb 是request或session作用域的bean
4. 如果 ./3 中条件不满足,则执行该beanName实例化
5. 如果requiredType类型参数不为空而且从上面得到的bean实例类型与requiredType不匹配 则调用类型转换器进行转换,转换成功直接返回转换后得bean实例,转换失败抛出BeanNotOfRequiredTypeException异常
6. 返回上面得到的bean实例 return (T) bean;
0 条评论
回复 删除
下一页