You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
note/framework-source-code/1、Spring Bean生命周期概述.md

185 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# <center>Spring启动主要流程</center>
Spring框架源码版本5.3.x
![Spring Bean生命周期](Spring%20Bean%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png)
### 框架源码的前置知识
* 设计模式
* 数据结构与算法
* 反射
* 多线程
* JVM
通过xml文件配置bean进行调试。
```xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" abstract="xxx" autowire="byName" autowire-candidate="default" depends-on="environment" init-method="afterPropertiesSet">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
```
```Java
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml")
XXX xxbean = context.getBean(XXX.class);
xxbean.method();
context.close();
```
#### SSM框架项目中spring处理bean的主要流程
* 加载bean定义文件一般是xml文件或者注解
* 解析bean定义文件
* 封装BeanDefinition
* 处理PostProcessor
* 准备监听器
* 创建代理(JDK或者Cglib),使用反射实例化
* 属性填充和初始化
* 销毁
beanFactory容器使用map保存创建的bean,map的key和value内容
|序号| Key | Value |
|----| ---- | ---- |
|1| String | Object |
|2| Class | Object |
|3| String | ObjectFactory |
|4| String | BeanDefinition |
|4| String | lambda表达式 |
## Spring创建Bean过程中用到的主要接口和类
* BeanDefinitionReader
* BeanDefinition
* BeanFactory
* FactoryBean
* DefaultListableBeanFactory
* ClassPathXmlApplicationContext
* BeanPostProcessor
* BeanFactoryPostProcessor
* Aware
* BeanNameAware
* AbstractAutoProxyCreator
* ConfigurationClassPostProcessor
#### BeanDefinitionReader
&emsp;&emsp;指定带有Resource或者字符串参数的加载方法的bean definition的简单接口。根据定义格式(xml、properties、yaml、注解)具体的reader可以添加额外的加载和注册方法。
#### BeanDefinition
&emsp;&emsp;BeanDefinition描述带有属性值、构造器参数值、具体实现类的信息。
这是一个最小的接口主要使BeanFactoryPostProcessor可以自省和修改属性值和其他的bean元数据。
#### BeanFactory
&emsp;&emsp;访问Spring Bean容器的根接口。它是bean容器的基本客户端视图进一步的接口如ListableBeanFactory和ConfigurableBeanFactory可用于指定的目的。
&emsp;&emsp;这个接口被持有许多bean定义的对象实现每一个对象都由字符串唯一确定。依据bean定义factory将返回一个容器化对象的独立实例(原型设计模式),或者一个单例的共享对象(单例设计模式的一个更好的替代方案该实例在factory内部是单例的)。那种类型的实例会被返回依赖于factory的配置API是相同的。从Spring2.0开始,根据具体应用上下文,更多的范围可以被使用(比如web环境中的request和session)。
&emsp;&emsp;这种方法的要点是BeanFactory是应用程序组件的中央注册表并且集中了应用程序组件的配置(例如单个对象不再需要读取属性文件)。可以通过&lt;Expert One-on-One J2EE Design and Development&gt;的第4章和11章了解这种方式的优点。(到底是啥优点?)
&emsp;&emsp;一般来讲依靠DI(push配置)通过set或者构造方法配置应用对象是比使用任何形式比如查找BeanFactory拉取配置要好的。Spring的依赖注入功能是使用BeanFactory接口和它的子接口实现的。
&emsp;&emsp;通常一个BeanFactory将会加载保存在配置源(比如xml文档)中的bean定义使用org.springframework.beans包配置bean。但是实现可以简单地返回它根据需要直接在 Java 代码中创建的 Java 对象。bean定时可以被怎样储存是没有任何限制的可以使用LDAP、RDBMS、XML、properties文件等。鼓励实现支持 bean 之间的引用(依赖注入)。
&emsp;&emsp;与ListableBeanFactory中的方法相比如果它是一个HierarchicalBeanFactory这个接口的所有操作也会检查父工厂。如果一个bean没有在这个工厂实例中找到会在直接父工厂中查找。这个工厂实例中的 bean 应该覆盖任何父工厂中的同名 bean。
&emsp;&emsp;BeanFactory的实现类应该尽可能支持标准的bean生命周期接口。所有的初始化方法和顺序为
* BeanNameAware's {@code setBeanName}
* BeanClassLoaderAware's {@code setBeanClassLoader}
* BeanFactoryAware's {@code setBeanFactory}
* EnvironmentAware's {@code setEnvironment}
* EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
* ResourceLoaderAware's {@code setResourceLoader}
* ApplicationEventPublisherAware's {@code setApplicationEventPublisher} (only applicable when running in an application context)
* MessageSourceAware's {@code setMessageSource} (only applicable when running in an application context)
* ApplicationContextAware's {@code setApplicationContext} (only applicable when running in an application context)
* ServletContextAware's {@code setServletContext} (only applicable when running in an application context)
* {@code postProcessBeforeInitialization} methods of BeanPostProcessors (only applicable when running in a web application context)
* InitializingBean's {@code afterPropertiesSet}
* a custom {@code init-method} definition
* {@code postProcessAfterInitialization} methods of BeanPostProcessors
&emsp;&emsp;bean工厂关闭的时候会调用DestructionAwareBeanPostProcessors的postProcessBeforeDestruction()方法DisposableBean的destroy()方法自定义的destroy-method方法
#### FactoryBean
&emsp;&emsp;由BeanFactory中使用的对象实现的接口这些对象本身就是单个对象的工厂。 如果一个 bean 实现了这个接口,它就被用作一个对象的工厂来暴露,而不是直接作为一个将暴露自己的 bean 实例。
&emsp;&emsp;实现此接口的 bean 不能用作普通 bean。 FactoryBean 以 bean 样式定义,但为 bean 引用暴露的对象 getObject() 始终是它创建的对象。
&emsp;&emsp;FactoryBeans 可以支持单例和原型并且可以根据需要懒惰地创建对象也可以在启动时急切地创建对象。SmartFactoryBean接口允许公开更细粒度的行为元数据。
&emsp;&emsp;此接口在框架本身中大量使用,例如 AOP org.springframework.aop.framework.ProxyFactoryBean 或 org.springframework.jndi.JndiObjectFactoryBean。 它也可以用于自定义组件;但是,这仅适用于基础设施代码。
&emsp;&emsp;FactoryBean 是一个编程约定。实现不应该依赖于注解驱动的注入或其他反射设施。getObjectType() 和getObject() 调用可能在启动过程的早期到达,甚至在任何后处理器设置之前。 如果您需要访问其他 bean请实现BeanFactoryAware并以编程方式获取它们。
&emsp;&emsp;容器只负责管理 FactoryBean 实例的生命周期,而不负责管理 FactoryBean 创建的对象的生命周期。 因此,暴露的 bean 对象(例如 java.io.Closeable#close())上的 destroy 方法不会被自动调用。 相反FactoryBean 应该实现 DisposableBean 并将任何此类关闭调用委托给底层对象。
&emsp;&emsp;最后FactoryBean 对象参与包含 BeanFactory 的 bean 创建同步。 除了在 FactoryBean 本身(或类似的)中进行惰性初始化之外,通常不需要内部同步。
#### DefaultListableBeanFactory
&emsp;&emsp;Spring对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现基于 bean 定义元数据的成熟的 bean 工厂,可通过后处理器进行扩展。
&emsp;&emsp;典型用法是在访问bean前先注册所有 bean 定义(很可能是从一个bean定义文件中读取的)。在本地bean定义表中在预先解析的bean定义元数据上操作按照名称查找bean是一项廉价操作。
&emsp;&emsp;特定bean定义格式的reader都是被分开实现的而不是作为bean工厂的子类可以参考XmlBeanDefinitionReader。
&emsp;&emsp;对于ListableBeanFactory接口的替代实现可以参考StaticListableBeanFactory它管理已经存在的bean实例而不是根据bean定义创建新的bean。
#### ClassPathXmlApplicationContext
&emsp;&emsp;独立的 XML 应用程序上下文,从类路径中获取上下文定义文件,将普通路径解释为包含包路径的类路径资源名称(比如"mypackage/myresource.txt")。对于测试工具以及嵌入在 JAR 中的应用程序上下文很有用。
&emsp;&emsp;配置位置默认值可以通过 {@link #getConfigLocations} 覆盖,配置位置可以表示为具体文件,比如"myfiles/context.xml"或者Ant风格类型比如"myfiles/*-context.xml"(参考AntPathMatcher的java文档)。
&emsp;&emsp;注意:在多个配置位置的情况下,后面的 bean 定义将覆盖前面加载文件中定义的那些。 这可以用来通过额外的 XML 文件故意覆盖某些 bean 定义。
&emsp;&emsp;这是一个简单的、一站式便利的 ApplicationContext。考虑使用GenericApplicationContext类结合XmlBeanDefinitionReader进行更灵活的上下文设置。
#### BeanPostProcessor
&emsp;&emsp;允许自定义修改新 bean 实例的工厂钩子——例如,检查标记接口或使用代理包装 bean。
&emsp;&emsp;通常后处理器通过标记接口填充bean或类似的将实现{@link #postProcessBeforeInitialization},而用代理包装 bean 的后处理器通常会实现{@link #postProcessAfterInitialization}。
&emsp;&emsp;ApplicationContext可以在其 bean 定义中自动检测 BeanPostProcessor bean并将这些后处理器应用于随后创建的任何 bean。普通的 BeanFactory 允许后处理器的编程注册,将它们应用于通过 bean 工厂创建的所有 bean。
&emsp;&emsp;在 ApplicationContext 中自动检测到的 BeanPostProcessor bean 将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.Ordered 语义进行排序。相反,使用 BeanFactory 以编程方式注册的 BeanPostProcessor bean 将按注册顺序应用;对于以编程方式注册的后处理器,将忽略通过实现 PriorityOrdered 或 Ordered 接口表达的任何排序语义。此外, org.springframework.core.annotation.Order @Order 注解没有被考虑用于 BeanPostProcessor bean。
#### BeanFactoryPostProcessor
&emsp;&emsp;允许自定义修改应用程序上下文的 bean 定义的工厂钩子,调整上下文底层 bean 工厂的 bean 属性值。
&emsp;&emsp;对于针对系统管理员的自定义配置文件很有用,这些配置文件会覆盖在应用程序上下文中配置的 bean 属性。 请参阅 {@link PropertyResourceConfigurer} 及其具体实现,以了解满足此类配置需求的现成解决方案。
&emsp;&emsp;BeanFactoryPostProcessor 可以与 bean 定义交互并修改 bean 定义,但绝不能与 bean 实例交互。 这样做可能会导致 bean 过早实例化,违反容器并导致意外的副作用。 如果需要 bean 实例交互,请考虑改为实施 BeanPostProcessor。
&emsp;&emsp;ApplicationContext 自动检测其 bean 定义中的 BeanFactoryPostProcessor bean并在创建任何其他 bean 之前应用它们。 BeanFactoryPostProcessor 也可以通过 ConfigurableApplicationContext} 以编程方式注册。
&emsp;&emsp;在 ApplicationContext 中自动检测到的 BeanFactoryPostProcessor bean 将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.Ordered 语义进行排序。 相反,使用 ConfigurableApplicationContext 以编程方式注册的 BeanFactoryPostProcessor beans 将按注册顺序应用; 对于以编程方式注册的后处理器,将忽略通过实现 PriorityOrdered 或 Ordered 接口表达的任何排序语义。 此外, org.springframework.core.annotation.Order @Order 注释未被考虑用于 BeanFactoryPostProcessor beans。
#### Aware
&emsp;&emsp;一个标记父接口,指示一个 bean 有资格通过回调样式的方法被特定框架对象的 Spring 容器通知。 实际的方法签名由各个子接口确定,但通常应该只包含一个接受单个参数的返回 void 的方法。
&emsp;&emsp;请注意,仅实现 Aware 不提供默认功能。相反,处理必须显式完成,例如在 org.springframework.beans.factory.config.BeanPostProcessor 中。 有关处理特定 *Aware 接口回调的示例,请参阅 org.springframework.context.support.ApplicationContextAwareProcessor。
#### BeanNameAware
&emsp;&emsp;由想要在 bean 工厂中了解其 bean 名称的 bean 实现的接口。 请注意,通常不建议对象依赖于其 bean 名称,因为这表示对外部配置的潜在脆弱依赖,以及对 Spring API 的可能不必要的依赖。
#### AbstractAutoProxyCreator
&emsp;&emsp;org.springframework.beans.factory.config.BeanPostProcessor 的实现,用 AOP 代理包装每个符合条件的 bean在调用 bean 本身之前委托给指定的拦截器。
&emsp;&emsp;这个类区分“通用”拦截器:为它创建的所有代理共享,以及“特定”拦截器:每个 bean 实例唯一。不需要任何公共拦截器。如果有,则使用 interceptorNames 属性设置它们。 与 org.springframework.aop.framework.ProxyFactoryBean 一样,使用当前工厂中的拦截器名称而不是 bean 引用来允许正确处理原型顾问程序和拦截器:例如,支持有状态混合。#setInterceptorNames "interceptorNames" 条目支持任何建议类型。
&emsp;&emsp;如果有大量的 beans 需要用类似的代理包装,即委托给相同的拦截器,那么这种自动代理特别有用。 您可以向 bean 工厂注册一个这样的后处理器,而不是为 x 个目标 bean 重复定义 x 个代理,以达到相同的效果。
&emsp;&emsp;子类可以应用任何策略来决定是否要代理一个 bean例如 按类型、按名称、按定义详细信息等。它们还可以返回应仅应用于特定 bean 实例的其他拦截器。 一个简单的具体实现是 {@link BeanNameAutoProxyCreator},通过给定名称识别要代理的 bean。
&emsp;&emsp;可以使用任意数量的 TargetSourceCreator 实现来创建自定义目标源:例如,池化原型对象。 即使没有建议,自动代理也会发生,只要 TargetSourceCreator 指定自定义 org.springframework.aop.TargetSource。 如果没有设置 TargetSourceCreators或者没有匹配项默认情况下将使用 org.springframework.aop.target.SingletonTargetSource 来包装目标 bean 实例。
#### ConfigurationClassPostProcessor
&emsp;&emsp;启动过程中处理@Configuration注解。通过\<context:annotation-config/>或者\<context:component-scan/>标签注册也可以通过其他BeanFactoryPostProcessor手动注册。他实现了PriorityOrdered接口@Configuration注解修饰的类中所有具有bean定义的方法在所有BeanFactoryPostProcessor执行之前注册。