Spring IoC容器初始化源码—populateBeaninitializeBean填充Bean字段反射和setter方法依赖注入以及IoC容器初始化总结四万字 admin 2023-05-19 09:54:02 篇首语:本文由小编为大家整理,主要介绍了Spring IoC容器初始化源码—populateBeaninitializeBean填充Bean字段反射和setter方法依赖注入以及IoC容器初始化总结四万字相关的知识,希望对你有一定的参考价值。 基于最新Spring 5.x,详细介绍了bean的“初始化过程”,主要包括applyMergedBeanDefinitionPostProcessors、populateBean、initializeBean、registerDisposableBeanIfNecessary核心方法,最后对Spring IoC容器初始化进行了总结! 上一篇文章:Spring IoC容器初始化源码(7)—createBean实例化Bean以及构造器自动注入中,我们主要讲解了ClassPathXmlApplicationContext IoC容器初始化的refresh方法中的createBean方法的全部流程以及该方法内部的createBeanInstance方法的源码——bean的创建以及基于构造器的自动注入的过程,即bean的“实例化”。 现在我们继续向下学习refresh()方法的中的后面的内容,接下来就是bean的“初始化”过程,主要知识点包括:applyMergedBeanDefinitionPostProcessors方法查找解析各种回调注解或者自动注入注解、populateBean方法填充bean实例、initializeBean方法对bean实例进行各种回调、registerDisposableBeanIfNecessary方法尝试注册bean销毁回调方法。最后,我们会对这几篇文章讲解的Spring IoC容器初始化源码进行简单的总结! Spring IoC容器初始化源码 系列文章 Spring IoC容器初始化源码(1)—setConfigLocations设置容器配置信息 Spring IoC容器初始化源码(2)—prepareRefresh准备刷新、obtainFreshBeanFactory加载XML资源、解析<beans/>标签 Spring IoC容器初始化源码(3)—parseDefaultElement、parseCustomElement解析默认、扩展标签,registerBeanDefinition注册Bean定义 Spring IoC容器初始化源码(4)—<context:component-scan/>标签解析、spring.components扩展点、自定义Spring命名空间扩展点 Spring IoC容器初始化源码(5)—prepareBeanFactory、invokeBeanFactoryPostProcessors、registerBeanPostProcessors方法 Spring IoC容器初始化源码(6)—finishBeanFactoryInitialization实例化Bean的整体流程以及某些扩展点 Spring IoC容器初始化源码(7)—createBean实例化Bean的整体流程以及构造器自动注入 Spring IoC容器初始化源码(8)—populateBean、initializeBean填充Bean、字段反射和setter方法依赖注入以及IoC容器初始化总结【四万字】 < context:property-placeholder/>标签以及PropertySourcesPlaceholderConfigurer占位符解析器源码深度解析 三万字的ConfigurationClassPostProcessor配置类后处理器源码深度解析 基于JavaConfig的AnnotationConfigApplicationContext IoC容器初始化源码分析 文章目录 Spring IoC容器初始化源码 系列文章1 applyMergedBeanDefinitionPostProcessors应用MergedBeanDefinitionPostProcessor后处理器1.1 CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调1.1.1 InitDestroyAnnotationBeanPostProcessor. postProcessMergedBeanDefinition回调1.1.1.1 findLifecycleMetadata处理@PostConstruct、@PreDestroy注解1.1.1.1.1 buildLifecycleMetadata创建LifecycleMetadata1.1.1.1.2 LifecycleElement生命周期回调方法包装 1.1.1.2 checkConfigMembers检查配置 1.1.2. findResourceMetadata处理@WebServiceRef、@EJB、@Resource注解1.1.2.1 buildResourceMetadata获取InjectionMetadata1.1.2.2 checkConfigMembers检查配置 1.2 AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调1.2.1 findAutowiringMetadata处理@Autowired、@Value、@Inject注解1.2.1.1 buildAutowiringMetadata获取InjectionMetadata 1.3 ApplicationListenerDetector.postProcessMergedBeanDefinition回调 2 addSingletonFactory添加单例工厂2.1 getEarlyBeanReference回调SmartInstantiationAwareBeanPostProcessor获取早期bean引用 2 populateBean填充bean实例2.1 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation回调2.2 autowireByName 基于byName的setter自动注入解析2.2.1 unsatisfiedNonSimpleProperties获取需要进行注入的非简单类型的“属性”名数组 2.3 autowireByType基于byType的setter自动注入解析2.4 InstantiationAwareBeanPostProcessor.postProcessProperties回调注解注入2.4.1 InjectionMetadata.inject注解注入2.4.2 InjectedElement.inject执行@WebServiceRef、@EJB、@Resource注解解析注入2.4.2.1 @Resource注解的基本解析2.4.2.2 ResourceElement. getResourceToInject解析@Resource获取资源用于注入2.4.2.2.1 getResource获取给定名称和类型的资源对象2.4.2.2.2.1 autowireResource获取自动注入的资源 2.4.2.3. checkPropertySkipping跳过属性 2.4.3 AutowiredFieldElement.inject执行@Autowired、@Value、@Inject字段注解解析注入2.4.4 AutowiredMethodElement.inject执行@Autowired、@Value、@Inject方法注解解析注入 2.5 applyPropertyValues属性setter装配2.5.1 setPropertyValues注入属性值2.5.1.1 setPropertyValue注入属性值2.5.1.1.1 processLocalProperty一般属性注入 3 initializeBean初始化bean实例3.1 invokeAwareMethods回调Aware的方法3.2 applyBeanPostProcessorsBeforeInitialization回调BeanPostProcessor.postProcessBeforeInitialization方法3.3 invokeInitMethods回调初始化方法3.4 applyBeanPostProcessorsAfterInitialization回调BeanPostProcessor.postProcessAfterInitialization方法 4 registerDisposableBeanIfNecessary注册销毁回调4.1 requiresDestruction判断是否需要销毁4.1.1 hasDestroyMethod是否具有销毁回调方法4.1.2 hasApplicableProcessors是否需要被后处理器销毁4.1.2.1 InitDestroyAnnotationBeanPostProcessor.requiresDestruction回调检查@PreDestroy注解 4.2 DisposableBeanAdapter可销毁bean适配器4.2.1 inferDestroyMethodIfNecessary推断销毁方法4.2.2 filterPostProcessors过滤DestructionAwareBeanPostProcessor 4.3 registerDisposableBean注册disposableBeans 5 finishRefresh完成刷新5.1 clearResourceCaches清除资源缓存5.2 initLifecycleProcessor初始化生命周期处理器LifecycleProcessor5.3 onRefresh回调SmartLifecycle.start()方法5.3.1 AbstractApplicationContext.start 6 IoC容器初始化总结 我们接着上一篇文章继续向下讲doCreateBean方法在createBeanInstance之后的源码! 1 applyMergedBeanDefinitionPostProcessors应用MergedBeanDefinitionPostProcessor后处理器 createBeanInstance实例化bean完毕之后,方法或者字段依赖注入之前,会接着调用applyMergedBeanDefinitionPostProcessors方法,正如方法名那样,这个方法将会查找全部MergedBeanDefinitionPostProcessor类型的后处理器,回调它们的postProcessMergedBeanDefinition方法,该方法可以改变已合并的bean定义,当然还能做更多的事情,最常见的就是解析字段和方法上的某些注解。 很多的后处理器都是MergedBeanDefinitionPostProcessor的子类型,比如CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor、ApplicationListenerDetector这三个常见的后处理器,它们的postProcessMergedBeanDefinition方法都将在这里被依次回调,即在bean实例化之后被回调。 CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法最开始还会调用父类InitDestroyAnnotationBeanPostProcessor的同名方法用于处理方法上的@PostConstruct、@PreDestroy注解,随后自己处理字段和方法上的@WebServiceRef、@EJB、@Resource注解。AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法用于处理方法和字段上的@Autowired、@Value、@Inject注解。ApplicationListenerDetector的postProcessMergedBeanDefinition方法用于记录ApplicationListener类型的bean是否是单例的,后面监听器过滤的时候才会用到。 注意,在这一步(applyMergedBeanDefinitionPostProcessors方法)仅仅是简单解析这些注解,相当于查找并缓存起来,后面某些时候,比如依赖注入的时候会被再次调用,到时候将进一步深度解析它们的配置属性和功能。 /** * 将MergedBeanDefinitionPostProcessors后处理器应用于指定的 bean 定义,调用其postProcessMergedBeanDefinition方法。 * * @param mbd 已合并的bean定义 * @param beanType bean的类型 * @param beanName beanName */protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) //获取、遍历全部已注册的后处理器 for (BeanPostProcessor bp : getBeanPostProcessors()) //如果bp属于MergedBeanDefinitionPostProcessor if (bp instanceof MergedBeanDefinitionPostProcessor) //那么强制转型 MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; //回调postProcessMergedBeanDefinition方法,该方法可用于修改给定bean的已合并的RootBeanDefinition bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); 1.1 CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调 该方法首先会调用父类InitDestroyAnnotationBeanPostProcessor的同名方法用于处理PostConstruct、PreDestroy注解。随后自己处理@WebServiceRef、@EJB、@Resource注解。 /** * CommonAnnotationBeanPostProcessor的方法 * * 调用父类InitDestroyAnnotationBeanPostProcessor的同名方法用于处理:PostConstruct、PreDestroy注解。 * 随后自己处理:@WebServiceRef、@EJB、@Resource注解。 * * @param beanDefinition 已合并的bean定义 * @param beanType bean的类型 * @param beanName beanName */@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) /*调用父类的InitDestroyAnnotationBeanPostProcessor的同名方法用于处理@PostConstruct、@PreDestroy注解*/ super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); /*自己处理@WebServiceRef、@EJB、@Resource注解*/ InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null); //检查配置 metadata.checkConfigMembers(beanDefinition); 很多后处理器在创建的时候会初始化很多的属性,CommonAnnotationBeanPostProcessor也不例外,最重要的是它会设置父类的init 和 destroy 注解类型默认为javax.annotation.PostConstruct和javax.annotation.PreDestroy。因此我们也可以自定义初始化和销毁注解。 /** * CommonAnnotationBeanPostProcessor的构造器 * * 设置父类的init 和 destroy 注解类型为javax.annotation.PostConstruct和javax.annotation.PreDestroy * 因此我们也可以自定义初始化和销毁注解 */public CommonAnnotationBeanPostProcessor() //设置父类InitDestroyAnnotationBeanPostProcessor的order属性 //用于排序 setOrder(Ordered.LOWEST_PRECEDENCE - 3); //设置父类InitDestroyAnnotationBeanPostProcessor的initAnnotationType属性 //表示初始化回调注解的类型 setInitAnnotationType(PostConstruct.class); //设置父类InitDestroyAnnotationBeanPostProcessor的destroyAnnotationType属性 //表示销毁回调注解的类型 setDestroyAnnotationType(PreDestroy.class); //设置自己的ignoredResourceTypes属性 //表示在解析@Resource注解时忽略给定的资源类型。 ignoreResourceType("javax.xml.ws.WebServiceContext"); 1.1.1 InitDestroyAnnotationBeanPostProcessor. postProcessMergedBeanDefinition回调 内部就是调用两个方法,findLifecycleMetadata用于解析该Class,获取全部具有@PostConstruct、@PreDestroy注解的方法的LifecycleMetadata包装对象。 checkConfigMembers用于检查配置信息,主要是防止后续重复调用回调方法。 /** * InitDestroyAnnotationBeanPostProcessor的方法 * * 处理@PostConstruct、@PreDestroy注解 * * @param beanDefinition 已合并的bean定义 * @param beanType bean的类型 * @param beanName beanName */@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) //获取生命周期相关的元数据对象,LifecycleMetadata是该类的内部类,内部持有当前的class以及对应的具有@PostConstruct、@PreDestroy注解的方法 LifecycleMetadata metadata = findLifecycleMetadata(beanType); //检查配置信息 metadata.checkConfigMembers(beanDefinition); 1.1.1.1 findLifecycleMetadata处理@PostConstruct、@PreDestroy注解 用于获取该Class的LifecycleMetadata,内部保存了具有@PostConstruct、@PreDestroy注解的方法。 首先尝试从lifecycleMetadataCache缓存中获取,没有缓存就进行解析,解析之后会将结果存入缓存,后续相同的Class不再解析。 /** * InitDestroyAnnotationBeanPostProcessor的方法 * * 获取LifecycleMetadata * * @param clazz bean的类型 * @return LifecycleMetadata对象,内部持有当前的class以及对应的具有@PostConstruct、@PreDestroy注解的方法 */private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) //如果lifecycleMetadataCache缓存为null if (this.lifecycleMetadataCache == null) // 创建该类型的LifecycleMetadata return buildLifecycleMetadata(clazz); //否则,查询缓存 LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz); //如果存在该类型的缓存,从缓存获取 if (metadata == null) synchronized (this.lifecycleMetadataCache) //加锁之后再次获取,防止并发 metadata = this.lifecycleMetadataCache.get(clazz); //如果metadata为null if (metadata == null) //那么创建该类型的LifecycleMetadata metadata = buildLifecycleMetadata(clazz); //存入缓存汇中 this.lifecycleMetadataCache.put(clazz, metadata); //返回 return metadata; //如果缓存不为null,那么直接返回缓存 return metadata; 1.1.1.1.1 buildLifecycleMetadata创建LifecycleMetadata 关键方法就是buildLifecycleMetadata方法,用于解析该Class的LifecycleMetadata。 大概逻辑是:遍历该Class及其父Class,查找具有@PostConstruct和@PreDestroy注解的方法,封装成为一个LifecycleElement对象,存入两个集合中,父类的回调方法的LifecycleElement在集合的前面,最后会根据该Class以及初始化、销毁集合创建一个LifecycleMetadata对象返回。 //------InitDestroyAnnotationBeanPostProcessor的相关属性------/** * 初始化回调注解的类型,默认@PostConstruct */@Nullableprivate Class<? extends Annotation> initAnnotationType;/** * 销毁回调注解的类型,默认@PreDestroy */@Nullableprivate Class<? extends Annotation> destroyAnnotationType;/** * 排序优先级 */private int order = Ordered.LOWEST_PRECEDENCE;/** 1. InitDestroyAnnotationBeanPostProcessor的方法 2. 3. 根据给定的类型,创建LifecycleMetadata 4. 遍历该类及其父类查找初始化注解和销毁注解 5. 6. @param clazz bean的类型 7. @return LifecycleMetadata对象,内部持有当前的class以及对应的具有@PostConstruct、@PreDestroy注解的方法 */private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) //确定给定类是否是承载指定注释的候选项(在类型、方法或字段级别)。 //如果任何一个注解的全路径名都不是以"java."开始,并且该Class全路径名以"start."开始,或者Class的类型为Ordered.class,那么返回false,否则其他情况都返回true if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) //如果该类型不能承载这两个主机,那么直接返回emptyLifecycleMetadata,这是一个空的LifecycleMetadata实例 return this.emptyLifecycleMetadata; //到这里表示允许承载,那么尝试查找 //初始化回调方法集合 List<LifecycleElement> initMethods = new ArrayList<>(); //销毁回调方法集合 List<LifecycleElement> destroyMethods = new ArrayList<>(); //目标类型 Class<?> targetClass = clazz; /*循环遍历该类及其父类,直到父类为Object*/ do //当前的初始化回调方法集合 final List<LifecycleElement> currInitMethods = new ArrayList<>(); //当前的销毁回调方法集合 final List<LifecycleElement> currDestroyMethods = new ArrayList<>(); /* * 循环过滤所有的方法(不包括构造器),查找被初始化注解@PostConstruct和销毁注解@PreDestroy标注的方法 * 这两个注解都是标注在方法上的,构造器上没有标注 */ ReflectionUtils.doWithLocalMethods(targetClass, method -> //如果initAnnotationType不为null,并且存在该类型的注解 if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) //那么根据当前方法新建一个LifecycleElement,添加到currInitMethods中 //LifecycleElement表示了一个具有@PostConstruct、@PreDestroy等生命周期注解的方法 LifecycleElement element = new LifecycleElement(method); currInitMethods.add(element); if (logger.isTraceEnabled()) logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); //如果initAnnotationType不为null,并且存在该类型的注解 if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) //那么根据当前方法新建一个LifecycleElement,添加到currDestroyMethods中 currDestroyMethods.add(new LifecycleElement(method)); if (logger.isTraceEnabled()) logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method); ); //currInitMethods集合整体添加到initMethods集合的开头 initMethods.addAll(0, currInitMethods); //currDestroyMethods集合整体添加到destroyMethods集合的开头 destroyMethods.addAll(currDestroyMethods); //获取下一个目标类型,是当前类型的父类型 targetClass = targetClass.getSuperclass(); //如果目标类型不为null并且不是Object.class类型,那么继续循环,否则结束循环 while (targetClass != null && targetClass != Object.class); //如果initMethods和destroyMethods都是空集合,那么返回一个空的LifecycleMetadata实例 //否则返回一个新LifecycleMetadata,包含当前的class以及对应的找到的initMethods和destroyMethods return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new LifecycleMetadata(clazz, initMethods, destroyMethods)); 1.1.1.1.2 LifecycleElement生命周期回调方法包装 LifecycleElementInit是DestroyAnnotationBeanPostProcessor的内部类,一个LifecycleElement对象封装了一个生命周期回调方法,及其标识符,标识符用于方法重复调用。 在创建LifecycleElement的时候做两件事: 进行参数校验,只有0个参数的方法才能作为初始化或者销毁回调方法,否则抛出异常:Lifecycle method annotation requires a no-arg method……计算当前方法的identifier标识符,用于避免重复调用回调方法。如果是私有方法,则标识符为该方法的全路径名;如果是非私有方法,则标识符为该方法简单名字。 /** * InitDestroyAnnotationBeanPostProcessor的内部类 * 一个LifecycleElement对象封装了一个回调方法,及其标识符,标识符用于方法重复调用 */private static class LifecycleElement /** * 当前方法 */ private final Method method; /** * 标识符 */ private final String identifier; public LifecycleElement(Method method) //如果方法参数不为0,那么抛出异常,从这里可知,初始化和销毁回调方法都不能有参数 if (method.getParameterCount() != 0) throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method); this.method = method; //计算identifier //如果是私有方法,则标识符为:该方法的全路径名,如果是非私有方法,则标识符为该方法简单名字 this.identifier = (Modifier.isPrivate(method.getModifiers()) ? ClassUtils.getQualifiedMethodName(method) : method.getName()); 1.1.1.2 checkConfigMembers检查配置 设置相关的方法到checkedInitMethods和checkedDestroyMethods中,后续直接调用。同时设置到mbd的externallyManagedInitMethods中,防止重复调用同一个方法,后面会讲。 //-------LifecycleMetadata的属性----------/** * 目标类型 */private final Class<?> targetClass;/** * 初始化回调方法集合 */private final Collection<LifecycleElement> initMethods;/** * 销毁回调方法集合 */private final Collection<LifecycleElement> destroyMethods;/** * 检查的初始化回调方法集合 */@Nullableprivate volatile Set<LifecycleElement> checkedInitMethods;/** * 检查的销毁回调方法集合 */@Nullableprivate volatile Set<LifecycleElement> checkedDestroyMethods;/** * LifecycleMetadata的构造器 * @param targetClass 目标类型 * @param initMethods 初始化回调方法 * @param destroyMethods 销毁回调方法 */public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods, Collection<LifecycleElement> destroyMethods) //为属性赋值 this.targetClass = targetClass; this.initMethods = initMethods; this.destroyMethods = destroyMethods;/** * LifecycleMetadata的方法 * * 检查配置,设置相关的方法到checkedInitMethods和checkedDestroyMethods中,后续直接调用 * 同时设置到mbd的externallyManagedInitMethods中,防止重复调用同一个方法 * @param beanDefinition 当前bean定义 */public void checkConfigMembers(RootBeanDefinition beanDefinition) //创建被检查的初始化回调方法集合 Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size()); //遍历检查initMethods for (LifecycleElement element : this.initMethods) //获取标识符 String methodIdentifier = element.getIdentifier(); //如果mbd的externallyManagedInitMethods不包含当前回调方法 if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) //设置到mbd的externallyManagedInitMethods中 beanDefinition.registerExternallyManagedInitMethod(methodIdentifier); //设置到checkedInitMethods中 checkedInitMethods.add(element); if (logger.isTraceEnabled()) logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + element); Set<LifecycleElement> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size()); for (LifecycleElement element : this.destroyMethods) //获取标识符 String methodIdentifier = element.getIdentifier(); //如果mbd的externallyManagedInitMethods不包含当前回调方法 if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) //设置到mbd的externallyManagedInitMethods中以上是关于Spring IoC容器初始化源码—populateBeaninitializeBean填充Bean字段反射和setter方法依赖注入以及IoC容器初始化总结四万字的主要内容,如果未能解决你的问题,请参考以下文章 阈值分割算子之OSTU算法 如何在library中使用productFlavors 您可能还会对下面的文章感兴趣: 相关文章 浏览器打不开网址提示“ERR_CONNECTION_TIMED_OUT”错误代码的解决方法 如何安装ocx控件 VMware的虚拟机为啥ip地址老是自动变化 vbyone和EDP区别 linux/debian到底怎么重启和关机 苹果平板键盘被弄到上方去了,如何调回正常? 机器学习常用距离度量 如何查看kindle型号