其它

(一)给源码导入到Spring工程里面

先下载源码
https://gitee.com/Z201/spring-framework.git


然后到Spring项目里面运行gradlew.bat重新编译

然后在项目根文件夹cmd 运行 gradlew :spring-oxm:compileTestJava 编译Spring项目


idea项目点击 [Project Settings] — [Libraries] —
找到 [Maven: org.springframework:spring-context:5.1.3.RELEASE] spring-context 可能版本号不到,

点击 加号
E:\ZJJ_Neaten5.10\spring-framework\spring-context\build\libs\spring-context-5.1.3.RELEASE.jar
SpringIOCDI源码[老的有时间整理一下] - 图1

然后还点击上面的加号,添加 source文件:
E:\ZJJ_Neaten5.10\spring-framework\spring-context
添加上面这个路径的文件夹,直接添加文件夹,


添加完了把原来导入Maven仓库的删除掉.

如果debug不能打断点.

是原因.class文件和源码文件对应不上了,解决方式是给源码文件(Spring源码文件,不是项目源码),重写打包 重写编译.
Gradle 项目方式 , 找到当前项目 Tasks — build — jar 双击一下即可 , 方式和Maven差不多.

为什么不用Maven的源码包
因为Maven的源码包打包之后是不可编辑的,而Gradle打完包是可以编辑的,我们可以一边跑debug断点一边去编辑.

(二)Spring框架功能整体介绍

SpringIOCDI源码[老的有时间整理一下] - 图2

1.Spring Core Container:

模块作用: Core 和 Beans 模块是框架的基础部分,提供 IoC (转控制)和依赖注入特性。 这里的基础 概念是 BeanFactory,它提供对 Factory 模式的经典实现来消除对程序’性单例模式的需要,并真 正地允许你从程序逻辑中分离出依赖关系和配置
1. Core:主要包含 Spring 框架基本的核心工具类, Spring 的其他组件都要用到这个包 里的类, Core模块是其他组件的基本核心。

2.Beans (BeanFacotry的作用):它包含访问配直文件、创建和管理 bean 以及进行 Inversion of Control I Dependency Injection ( IoC/DI )操作相关的所有类
Beans和Core是IOC核心功能的实现

3. Context(处理BeanFactory,,一下还是ApplicationContext的作用)模构建于 Core 和 Beans 模块基础之上,提供了一种类似JNDI 注册器的框 架式的对象访问方法。 Context 模块继承了 Beans 的特性,为 Spring 核心提供了大量 扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对 Context 的透明创 建的支持。 Context 模块同时也支持 J2EE 的一些特性, ApplicationContext 接口是 Context 模块的关键本质区别:(使用BeanFacotry的bean是延时加载的,ApplicationContext是非延时加载的)

4.Expression Language模块提供了强大的表达式语言,用于在运行时查询和操纵对象。 它是 JSP 2.1 规范中定义的 unifed expression language 的扩展。 该语言支持设直/获取属 性的值,属性的分配,方法的调用,访问数组上下文( accessiong the context of arrays )、 容器和索引器、逻辑和算术运算符、命名变量以及从Spring的 IoC 容器中根据名称检 索对象。 它也支持 list 投影、选择和一般的 list 聚合


BeanFactory和ApplicationContext的本质区别


spring使用BeanFactory来实例化、配置和管理对象,但是它只是一个接口,里面有一个getBean()方法。我们一般都不直接用BeanFactory,而是用它的实现类ApplicationContext,这个类会自动解析我们配置的applicationContext.xml,然后根据我们配置的bean来new对象,将new好的对象放进一个Map中,键就是我们bean的id,值就是new的对象。
BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。

//ApplicationContext 继承了ListableBeanFactory接口
public interface ApplicationContext extends EnvironmentCapable,
ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}

//ListableBeanFactory接口又继承了BeanFactory 接口
public interface ListableBeanFactory extends BeanFactory {
}



BeanFactory是SpringIOC容器的顶层接口。ApplicationContext是它的子接口。


1.ApplicationContext是实现类,继承ListableBeanFactory(继承BeanFactory),功能更多.
2.ApplicationContext默认立即加载(也可以说只要一解析配置文件就会马上创建对象并存入容器里面),可以指定为懒加载策略(因为ApplicationContext的父类是BeanFactory,必然具备父类接口的功能,所以也支持懒加载策略)
BeanFactory懒加载(在创建bean对象的时候,不会加载,在第一次使用对象来时候才去创建)


Spring 容器并不是只有一个。Spring 自带了多个容器实现,可以归为两种不同的类型。
bean 工厂(由org.springframework.beans.factory.BeanFactory接口定义)是最简单的容器,提供基本的 DI 支持。
应用上下文(由org.springframework.context.ApplicationContext接口定义)基于 BeanFactory 构建,并提供应用框架级别的服务,例如从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者。


工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
• MessageSource, 提供国际化的消息访问
• 资源访问,如URL和文件
• 事件传播
• 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
1.利用MessageSource进行国际化
BeanFactory是不支持国际化功能的,因为BeanFactory没有扩展Spring中MessageResource接口。相反,由于ApplicationContext扩展了MessageResource接口,因而具有消息处理的能力(i18N),具体spring如何使用国际化,以后章节会详细描述。

2.强大的事件机制(Event)
基本上牵涉到事件(Event)方面的设计,就离不开观察者模式。不明白观察者模式的朋友,最好上网了解下。因为,这种模式在java开发中是比较常用的,又是比较重要的。
ApplicationContext的事件机制主要通过ApplicationEvent和ApplicationListener这两个接口来提供的,和java swing中的事件机制一样。即当ApplicationContext中发布一个事件的时,所有扩展了ApplicationListener的Bean都将会接受到这个事件,并进行相应的处理。

Spring提供了部分内置事件,主要有以下几种:
ContextRefreshedEvent :ApplicationContext发送该事件时,表示该容器中所有的Bean都已经被装载完成,此ApplicationContext已就绪可用
ContextStartedEvent:生命周期 beans的启动信号
ContextStoppedEvent: 生命周期 beans的停止信号
ContextClosedEvent:ApplicationContext关闭事件,则context不能刷新和重启,从而所有的singleton bean全部销毁(因为singleton bean是存在容器缓存中的)

虽然,spring提供了许多内置事件,但用户也可根据自己需要来扩展spring中的事物。注意,要扩展的事件都要实现ApplicationEvent接口。

3.底层资源的访问
ApplicationContext扩展了ResourceLoader(资源加载器)接口,从而可以用来加载多个Resource,而BeanFactory是没有扩展ResourceLoader

4.对Web应用的支持
与BeanFactory通常以编程的方式被创建不同的是,ApplicationContext能以声明的方式创建,如使用ContextLoader。当然你也可以使用ApplicationContext的实现之一来以编程的方式创建ApplicationContext实例 。

5.其它区别
1).BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。

2).BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册


2.Spring Data Access/Integration

1.JDBC模块提供了一个 JDBC 抽象层,它可以消除冗长的 JDBC 编码和解析数据库厂 商特有的错误代码。
这个模块包含了 Spring 对 JDBC 数据访问进行封装的所有类
2.2) ORM 模块为流行的对象-关系映射 API,
如 JPA、 JDO、 Hibernate、 iBatis 等,提供了 一个交互层。 利用 ORM 封装包,可以混合使用所
有 Spring 提供的特性进行 O/R 映射, 如前边提到的简单声 明性事务管理。
2.3)OXM 模块提供了一个对 ObjecνXML 映射实现的抽象层,
Object/XML 映射实现包括 JAXB、 Castor、 XMLBeans、 JiBX 和 XStrearn
2.4)JMS ( Java Messaging Service )
模块主要包含了 一些制造和消 费消息的特性。
2.5) Transaction
支持编程和声明性的事务管理,这些事务类必须实现特定的接口,并 且对所有的 POJO 都适用

3.Spring Web

Web 模块:提供了基础的面向 Web 的集成特性c 例如,多文件上传、使用 servlet listeners 初始化
IoC 容器以及一个面向 Web 的应用上下文。 它还包含 Spring 远程支持中 Web 的相关部分。

4.Spring Aop

4.1)Aspects 模块提供了对 AspectJ 的集成支持。
4.2)Instrumentation 模块提供了 class instrumentation 支持和 classloader 实现,使得可以在特
定的应用服务器上使用

5.Test

Test 模块支持使用 JUnit 和 TestNG 对 Spring 组件进行测试

(三)耦合概念




耦合:
指的就是程序中的依赖关系.包括控制关系,调用关系,数据传递关系,模块儿间联系越多,其耦合性越强,耦合高的时候,独立性就会很差,可重用性就不好。我们在实际开发中应该避免这种耦合。

耦合分类:
1. 内容耦合:当一个模块儿直接修改或操作另一个模块的数据时,或者一个模块不通过正常入口而转入另一个模块儿时,这样的耦合被称为内容耦合,内容耦合是最高程度的耦合,应该避免使用之.
2. 公共耦合:两个或者两个以上的模块儿共同引用一个全局数据项,这种耦合被称为公共耦合,在具有大量公共耦合的结构中,确定究竟是哪个模块儿给全局变量赋了一个特定的值是十分困难的,
3. 外部耦合: 一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表达传递该全局变量的信息,称之为外部耦合.
4. 控制耦合:一个模块儿通过接口向另一个模块儿传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合
5. 标记耦合: 若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块B和C之间存在一个标记耦合.
6. 数据耦合:模块之间通过参数来传递数据,那么被称为数据耦合,数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据
7. 非直接耦合:两个模块之间没有直接关系,他们之间的联系完全是通过主模块的控制和调用来实现的,


总结
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应该采用以下原则:
如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合.

在实际开发中我们应该做到:
编译期不依赖, 运行时才依赖

解决思路:
创建对象采用反射的方式来创建对象,而避免使用new关键字,
当我们反射创建对象时,又产生了新的问题:就是反射的全限定类名在类中写死了。
解决写死的问题:通过配置文件来配置(通过读取配置文件来获取要创建的对象的权限定类名)

(四)Spring的优点

(1)spring属于低侵入式设计,代码的污染极低;
(2)spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;

(3)Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。

(4)spring对于主流的应用框架提供了集成支持。


DefaultListableBeanFactory


DefaultListableBeanFactory作为一个比较通用的BeanFactory实现,它同时也实现了BeanDefinitionRegistry接口,因此它就承担了Bean的注册管理工作。从图中也可以看出,BeanFactory接口中主要包含getBean、containBean、getType、getAliases等管理bean的方法,而BeanDefinitionRegistry接口则包含registerBeanDefinition、removeBeanDefinition、getBeanDefinition等注册管理BeanDefinition的方法。

spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖,研究透它的前生今世对我们理解spring ioc的概念有着重要的作用。
该类主要是对bean的注册后的处理,是整个bean加载的核心部分.



DefaultListableBeanFactory的作用:
默认实现了ListableBeanFactory和BeanDefinitionRegistry接口,基于bean definition对象,是一个成熟的bean factroy。
最典型的应用是:在访问bean前,先注册所有的definition(可能从bean definition配置文件中)。使用预先建立的bean定义元数据对象,从本地的bean definition表中查询bean definition因而将不会花费太多成本。
DefaultListableBeanFactory既可以作为一个单独的beanFactory,也可以作为自定义beanFactory的父类。
注意:特定格式bean definition的解析器可以自己实现,也可以使用原有的解析器,如:
PropertiesBeanDefinitionReader和XmLBeanDefinitionReader。

参考:
https://www.cnblogs.com/davidwang456/p/4187012.html


SpringIOCDI源码[老的有时间整理一下] - 图3

BeanLisitableBeanFactory的脉络.


AliasRegister: 定义对alias的简单增删改查操作
SimpleAliasRegistry : 主要使用map作为alias的缓存,并对接口AliasRegister进行实现.
SingletonBeanRegistry : 定义对单例的注册及获取.
BeanFactory: 定义获取bean及bean的各种属性.
DefaultSingletonBeanRegistry: 对接口SingletonBeanRegistry各个函数的实现.
HierarchicalBeanFactory: 继承BeanFactory,也就是在BeanFactory定义的功能的基础上对parentFactory的支持
BeanDefinitionRegistry: 定义对BeanDefinition的各种增删改操作
FactoryBeanRegistrySupport: 在DefaultSingletonBeanRegistry 的基础上增加了对FactoryBean的特殊处理功能.
ConfigurableBeanFactory: 提供配置Factory的各种方法
ListableBeanFactory: 根据各种条件获取bean的配置清单.
AbstractBeanFactory: 综合FactoryBeanRegistrySupport和ConfigurableBeanFactory的功能.
AutowireCapableBeanFactory: 提供创建bean 和 自动注入 和 初始化以及应用bean的后处理器
AbstractAutowireCapableBeanFactory: 总和AbstractBeanFactory并对接口Autowire CapableBeanFactory进行实现
ConfigurableListableBeanFactory: BeanFactory的配置清单,指定忽略类型及接口等.
DefaultListableBeanFactory: 综合上面所有功能,主要是对bean注册后的处理.

XmlBeanFactory对DefaultListableBeanFactory类进行了扩展,主要用于从xml文档中读取BeanDefinition,对于注册及获取bean都是使用从父类DefaultListableBeanFactory继承方法实现,而唯独与父类不同的个性化实现是增加了XmlBeanDefinitionReader类型的reader属性,在XmlBeanFactory 中主要使用reader属性对资源文件进行读取和注册.




(一)beanDefinitionNames容器

private volatile List beanDefinitionNames = new ArrayList<>(256);

这个容器装载的是所有的beanDefinition的名称,这个容器是我们完成BeanDefinition注册的时候我们把所有的进去的BeanDefinition对应名称,加到这个容器里面来

(二)beanDefinitionMap容器

private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

可以根据BeanDefinition名字找到对应的BeanDefinition对象



XmlBeanDefinitionReader

xml配置文件的读取是Spring的重要的功能,因为Spring的大部分功能都是以配置作为切入点,那么我们可以从XmlBeanDefinitionReader中梳理一下资源文件读取,解析及注册的大致脉络,下面各个类的功能:
1. ResourceLoader: 定义资源加载器,主要应用于根据给定的资源文件地址返回对应的Resource.
2. BeanDefinitionReader 主要定义资源文件读取并转换为BeanDefinition的各个功能.
3. EnvironmentCapable: 定义获取Environment方法
4. DocumentLoader:定义从资源文件加载到转换为Document的功能
5. AbstractBeanDefinitionReader: 对EnvironmentCapable,BeanDefinitionReader类定义的功能进行实现.
6. BeanDefinitionDocumentReader: 定义读取Document并注册BeanDefinition功能.
7. BeanDefinitionParseDelegate:定义解析Element的各种方法





//*

BeanDefinition



Spring进行实例化必须要有的对象,一个类要想实例化,必须要包装成BeanDefinition对象,然后给这个对象相应的属性设置值.在BeanDefinition里面的Class属性是类的权限定类名,Spring实例化一个类,只认识BeanDefinition对象.

BeanDefinition 在 spring 中贯穿始终,spring 要根据 BeanDefinition 对象来实例化 bean,只要把解析的xml里面的bean标签和自定义标签,扫描的注解类封装成 BeanDefinition 对象,spring才能实例化 bean.
BeanDefinition 就约束了我们Spring在实例化一个类的时候的一些行为(比如是否是懒加载).我们要根据BeanDefinition的一些属性做一些在实例化过程中做一些相应的操作.

BeanDefinition对象就承担了这个责任:容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的所有必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等。当客户端向容器请求相应对象时,容器就会通过这些信息为客户端返回一个完整可用的bean实例。

(一)BeanDefinition 实现类

ChildBeanDefinition, GenericBeanDefinition, RootBeanDefinition

(二)ChildBeanDefinition

ChildBeanDefinition 是一种 bean definition,它可以继承它父类的设置,即
ChildBeanDefinition 对 RootBeanDefinition 有一定的依赖关系。
ChildBeanDefinition 从父类继承构造参数值,属性值并可以重写父类的方法,同
时也可以增加新的属性或者方法。(类同于 java 类的继承关系)。若指定初始化方
法,销毁方法或者静态工厂方法,ChildBeanDefinition 将重写相应父类的设置。
depends on,autowire mode,dependency check,sigleton,lazy init 一般由子类自行设定。

(三)GenericBeanDefinition

注意:从 spring 2.5 开始,提供了一个更好的注册 bean definition 类
GenericBeanDefinition,它支持动态定义父依赖,方法是
GenericBeanDefinition.setParentName(java.lang.String),GenericBeanDefinition 可
以有效的替代 ChildBeanDefinition 的绝大分部使用场合。
GenericBeanDefinition 是一站式的标准 bean definition,除了具有指定类、可
选的构造参数值和属性参数这些其它 bean definition 一样的特性外,它还具有通
过 parenetName 属性来灵活设置 parent bean definition。
通常, GenericBeanDefinition 用来注册用户可见的 bean definition(可见的
bean definition意味着可以在该类bean definition上定义post-processor来对bean
进行操作,甚至为配置 parent name 做扩展准备)。RootBeanDefinition /
ChildBeanDefinition 用来预定义具有 parent/child 关系的 bean definition。

(四)RootBeanDefinition

一个 RootBeanDefinition 定义表明它是一个可合并的 bean definition:即在spring beanFactory 运行期间,可以返回一个特定的 bean。RootBeanDefinition 可以作为一个重要的通用的 bean definition 视图。
RootBeanDefinition 用来在配置阶段进行注册 bean definition。然后,从 spring2.5 后,编写注册 bean definition 有了更好的的方法:GenericBeanDefinition。
GenericBeanDefinition 支持动态定义父类依赖,而非硬编码作为 root bean definition。

(五)BeanDefinition 中的属性




SpringIOCDI源码[老的有时间整理一下] - 图4

(1)、id:Bean 的唯一标识名。它必须是合法的 XMLID,在整个 XML 文档中唯一。
(2)、name:用来为 id 创建一个或多个别名。它可以是任意的字母符合。多个别名之间用逗号或空格分
开。
(3)、class:用来定义类的全限定名(包名+类名)。只有子类 Bean 不用定义该属性。
(4)、parent:子类 Bean 定义它所引用它的父类 Bean。这时前面的 class 属性失效。子类 Bean 会继承
父类 Bean 的所有属性,子类 Bean 也可以覆盖父类 Bean 的属性。注意:子类 Bean 和父类 Bean 是同一
个 Java 类。
(5)、abstract(默认为”false”):用来定义 Bean 是否为抽象 Bean。它表示这个 Bean 将不会被实
例化,一般用于父类 Bean,因为父类 Bean 主要是供子类 Bean 继承使用。
(7)、lazy-init(默认为“default”):用来定义这个 Bean 是否实现懒初始化。如果为“true”,它将
在 BeanFactory 启动时初始化所有的 SingletonBean。反之,如果为“false”,它只在 Bean 请求时才开
始创建 SingletonBean。
(8)、autowire(自动装配,默认为“default”):它定义了 Bean 的自动装载方式。

1、“no”:不使用自动装配功能。
2、“byName”:通过 Bean 的属性名实现自动装配。
3、“byType”:通过 Bean 的类型实现自动装配。
4、“constructor”:类似于 byType,但它是用于构造函数的参数的自动组装。
5、“autodetect”:通过 Bean 类的反省机制(introspection)决定是使用“constructor”还是使用“byType”。

(10)、depends-on(依赖对象):这个 Bean 在初始化时依赖的对象,这个对象会在这个 Bean 初始
化之前创建。
(11)、init-method:用来定义 Bean 的初始化方法,它会在 Bean 组装之后调用。它必须是一个无参数
的方法。
(12)、destroy-method:用来定义 Bean 的销毁方法,它在 BeanFactory 关闭时调用。同样,它也必
须是一个无参数的方法。它只能应用于 singletonBean。
(13)、factory-method:定义创建该 Bean 对象的工厂方法。它用于下面的“factory-bean”,表示
这个 Bean 是通过工厂方法创建。此时,“class”属性失效。
(14)、factory-bean:定义创建该 Bean 对象的工厂类。如果使用了“factory-bean”则“class”属性
失效。
(15)、autowire-candidate:采用 xml 格式配置 bean 时,将元素的 autowire-candidate
属性设置为 false,这样容器在查找自动装配对象时,将不考虑该 bean,即它不会被考虑作为其它 bean
自动装配的候选者,但是该 bean 本身还是可以使用自动装配来注入其它 bean 的。
(16)、MutablePropertyValues:用于封装标签的信息,其实类里面就是有一个 list,list
里面是 PropertyValue 对象,PropertyValue 就是一个 name 和 value 属性,用于封装标签
的名称和值信息
(17)、ConstructorArgumentValues:用于封装标签的信息,其实类里面就是有
一个 map,map 中用构造函数的参数顺序作为 key,值作为 value 存储到 map 中
(18)、MethodOverrides:用于封装 lookup-method 和 replaced-method 标签的信息,同样的类里
面有一个 Set 对象添加 LookupOverride 对象和 ReplaceOverride 对象

BeanDefinitionRegistry接口


BeanDefinitionRegistry抽象出bean的注册逻辑它大概有如下功能:
1. 以Map的形式注册bean
2. 根据beanName 删除和获取 beanDefiniation
3. 得到持有的beanDefiniation的数目
4. 根据beanName 判断是否包含beanDefiniation




容器启动时,会通过某种途径加载Configuration MetaData。除了代码方式比较直接外,在大部分情况下,容器需要依赖某些工具类,比如:BeanDefinitionReader,BeanDefinitionReader会对加载的Configuration MetaData进行解析和分析,并将分析后的信息组装为相应的BeanDefinition,最后把这些保存了bean定义的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器的启动工作就完成了。这个阶段主要完成一些准备性工作,更侧重于bean对象管理信息的收集,当然一些验证性或者辅助性的工作也在这一阶段完成。

参考:
https://blog.csdn.net/f641385712/article/details/89518940

PostProcessor

Spring中提供了很多PostProcessor供开发者进行拓展,例如:BeanPostProcessor、BeanFactoryPostProcessor、BeanValidationPostProcessor等一系列后处理器。他们的使用方式大多类似,了解其中一个并掌握他的使用方式,其他的可以触类旁通。

(一)beanPostProcessors

beanPostProcessors
这个容器装载了我们上下文的所有的BeanPostProcessor类的实例






(二)BeanPostProcessor

案例:ZJJSpring_2020/05/29 8:58:53_msj9e



 简单点来理解,就是spring会自动从它的所有的bean定义中检测BeanPostProcessor类型的bean定义,然后实例化它们,再将它们应用于随后创建的每一个bean实例,在bean实例的初始化方法回调之前调用BeanPostProcessor的postProcessBeforeInitialization的方法(进行bean实例属性的填充),在bean实例的初始化方法回调之后调用BeanPostProcessor的postProcessAfterInitialization的方法(可以进行bean实例的代理封装)


BeanPostProcessor,提供了在Spring容器里面所有bean初始化之前和之后插入自定义逻辑的能力。与BeanFactoryPostProcessor的区别是处理的对象不同,BeanFactoryPostProcessor是对beanfactory进行处理,注意,千万不要将BeanPostProcessor设置为延迟加载.

其存在于对象实例化阶段。跟BeanFactoryPostProcessor类似,它会处理容器内所有符合条件并且已经实例化后的对象。简单的对比,BeanFactoryPostProcessor处理bean的定义,而BeanPostProcessor则处理bean完成实例化后的对象。



public interface BeanPostProcessor {
//bean初始化方法调用前被调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//bean初始化方法调用后被调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}



postProcessBeforeInitialization()方法与postProcessAfterInitialization()分别对应图中前置处理和后置处理两个步骤将执行的方法。这两个方法中都传入了bean对象实例的引用,为扩展容器的对象实例化过程提供了很大便利,在这儿几乎可以对传入的实例执行任何操作。注解、AOP等功能的实现均大量使用了BeanPostProcessor,比如有一个自定义注解,你完全可以实现BeanPostProcessor的接口,在其中判断bean对象的脑袋上是否有该注解,如果有,你可以对这个bean实例执行任何操作,想想是不是非常的简单?

再来看一个更常见的例子,在Spring中经常能够看到各种各样的Aware接口,其作用就是在对象实例化完成以后将Aware接口定义中规定的依赖注入到当前实例中。比如最常见的ApplicationContextAware接口,实现了这个接口的类都可以获取到一个ApplicationContext对象。当容器中每个对象的实例化过程走到BeanPostProcessor前置处理这一步时,容器会检测到之前注册到容器的ApplicationContextAwareProcessor,然后就会调用其postProcessBeforeInitialization()方法,检查并设置Aware相关依赖。看看代码吧,是不是很简单:

private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}

}




运行顺序
===Spring IOC容器实例化Bean===
===调用BeanPostProcessor的postProcessBeforeInitialization方法===
===调用bean实例的初始化方法===
===调用BeanPostProcessor的postProcessAfterInitialization方法===
SpringIOCDI源码[老的有时间整理一下] - 图5
BeanPostProcessor实例

/
后置处理器:初始化前后进行处理工作
将后置处理器加入到容器中
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//
TODO Auto-generated method stub
System.out.println(“postProcessBeforeInitialization…”+beanName+”=>”+bean);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//
TODO Auto-generated method stub
System.out.println(“postProcessAfterInitialization…”+beanName+”=>”+bean);
return** bean;
}

}






1.处理BeanPostProcessor 的源码


注册
AbstractApplicationContext#refresh 调用registerBeanPostProcessors 将所有的BeanPostProcessor都进行了实例化,并注册到了beanFactory的beanPostProcessors容器属性中.


AbstractApplicationContext#refresh调用finishBeanFactoryInitialization调用 DefaultListableBeanFactory#preInstantiateSingletons调用getBean调用doGetBean调用

AbstractAutowireCapableBeanFactory#doCreateBean调用createBeanInstance创建bean实例对象(这个时候执行bean的构造方法),然后调用populateBean方法,对bean进行填充,注入相关依赖,之后再调用方法initializeBean,进行相关初始化工作.


先调用applyBeanPostProcessorsBeforeInitialization方法,执行每个BeanPostProcessor的postProcessBeforeInitialization,然后调用invokeInitMethods方法(这个方法主要是调用实现InitializingBean接口的afterPropertiesSet方法),执行bean的初始化方法,最后调用applyBeanPostProcessorsAfterInitialization方法,执行每个BeanPostProcessor的postProcessAfterInitialization方法。


从invokeInitMethods方法的实现可以看出,先执行afterPropertiesSet方法,然后再通过反射,执行init-method指定的方法。
总结

在初始化之前应用Bean后置处理器
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
初始化之后应用Bean后置处理器

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization




(三)内置BeanPostProcessor子类



org.springframework.context.annotation.CommonAnnotationBeanPostProcessor:支持@Resource注解的注入
org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor:支持@Required注解的注入
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:支持@Autowired注解的注入
org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor:支持@PersistenceUnit和@PersistenceContext注解的注入
org.springframework.context.support.ApplicationContextAwareProcessor:用来为bean注入ApplicationContext等容器对象
这些注解类的BeanPostProcessor,在spring配置文件中,可以通过这样的配置 ,自动进行注册。(spring通过ComponentScanBeanDefinitionParser类来解析该标签)

1.AutowiredAnnotationBeanPostProcessor


这个类的目的是扫描有没有@Autowired注解,

拿到类,通过反射拿到类里面的所有属性,挨个循环每个属性判断属性上是否有@Resources或者@Autowired注解等等,如果有上面的注解的话,把它们包装成一个对象,最后包装成一个集合. 最后又把这个集合包装成立一个metadata对象.

2.CommonAnnotationBeanPostProcessor


这个类的作用是专门对@PostConstruct和@PreDestroy注解的处理
参考:
https://blog.csdn.net/shenchaohao12321/article/details/81235571

(四)使用场景


其实只要我们弄清楚了BeanPostProcessor的执行时机:在bean实例化之后、初始化前后被执行,允许我们对bean实例进行自定义的修改;只要我们明白了这个时机点,我们就能分辨出BeanPostProcessor适用于哪些需求场景,哪些需求场景可以用BeanPostProcessor来实现
spring中有很多BeanPostProcessor的实现,我们接触的比较多的自动装配:AutowiredAnnotationBeanPostProcessor也是BeanPostProcessor的实现之一,关于自动装配我会在下篇博文中与大家一起探索


BeanFactoryPostProcessor


个人感觉没什么用.

BeanFactoryPostProcessor的主要作用是让你能接触到bean definitions,对bean definitions进行一定修改

BeanFactoryPostProcessor可以与bean definitions打交道,但是千万不要进行bean实例化(感觉这里应该说的是不要在BeanFactoryPostProcessor进行可能触发bean实例化的操作)。这么做可能会导致bean被提前实例化,会破坏容器造成预估不到的副作用。如果你需要hack到bean实例化过程,请考虑使用BeanPostProcessor。





实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置’order’属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息.



IoC容器负责管理容器中所有bean的生命周期,而在bean生命周期的不同阶段,Spring提供了不同的扩展点来改变bean的命运。在容器的启动阶段,BeanFactoryPostProcessor允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做一些额外的操作,比如修改bean定义的某些属性或者增加其他信息等。

如果要自定义扩展类,通常需要实现org.springframework.beans.factory.config.BeanFactoryPostProcessor接口,与此同时,因为容器中可能有多个BeanFactoryPostProcessor,可能还需要实现org.springframework.core.Ordered接口,以保证BeanFactoryPostProcessor按照顺序执行。Spring提供了为数不多的BeanFactoryPostProcessor实现,我们以PropertyPlaceholderConfigurer来说明其大致的工作流程。

在Spring项目的XML配置文件中,经常可以看到许多配置项的值使用占位符,而将占位符所代表的值单独配置到独立的properties文件,这样可以将散落在不同XML文件中的配置集中管理,而且也方便运维根据不同的环境进行配置不同的值。这个非常实用的功能就是由PropertyPlaceholderConfigurer负责实现的。

根据前文,当BeanFactory在第一阶段加载完所有配置信息时,BeanFactory中保存的对象的属性还是以占位符方式存在的,比如${jdbc.mysql.url}。当PropertyPlaceholderConfigurer作为BeanFactoryPostProcessor被应用时,它会使用properties配置文件中的值来替换相应的BeanDefinition中占位符所表示的属性值。当需要实例化bean时,bean定义中的属性值就已经被替换成我们配置的值。当然其实现比上面描述的要复杂一些,这里仅说明其大致工作原理,更详细的实现可以参考其源码。



@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(“MyBeanFactoryPostProcessor…postProcessBeanFactory…”);
int count = beanFactory.getBeanDefinitionCount();
String[] names = beanFactory.getBeanDefinitionNames();
System.out.println(“当前BeanFactory中有”+count+” 个Bean”);
System.out.println(Arrays.asList(names));
}

}







BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistry后置处理器,BeanDefinitionRegistryPostProcessor的作用是完成BeanDefinition的增删改查操作,哪个BeanDefinition先实例化,哪个BeanDefinition后实例化,需要排序.这个排序是在ConfigurationClassPostProcessor类里面做的.
如果在类上面有@Order注解的话,就会被进行排序了. 解析这个@Order注解就是在
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions内部有个sort过程进行排序.



PostProcessorRegistrationDelegate

PostProcessor注册委托类

PostProcessorRegistrationDelegate是AbstractApplicationContext委托执行postProcessors任务的工具类
这里的postProcessor包括两类 :

BeanFactoryPostProcessor
BeanPostProcessor

实际上BeanFactoryPostProcessor又细分为两类:

1. BeanDefinitionRegistryPostProcessor–BeanDefinitionRegistry后置处理器,BeanDefinitionRegistryPostProcessor的作用是完成BeanDefinition的增删改查操作
2. BeanFactoryPostProcessor–BeanFactory后置处理器



BeanDefinitionRegistryPostProcessor扩展自BeanFactoryPostProcessor,是一种特殊的BeanFactoryPostProcessor,在执行BeanFactoryPostProcessor的功能前,提供了可以添加bean definition的能力,允许在初始化一般bean前,注册额外的bean。例如可以在这里根据bean的scope创建一个新的代理bean。




如果一个实现类是BeanDefinitionRegistryPostProcessor,那么它的postProcessBeanDefinitionRegistry方法总是要早与它的postProcessBeanFactory方法被调用。

该工具类位于包package org.springframework.context.support;

(一)两个主要功能

1.执行 BeanFactoryPostProcessor


背景介绍 :
1.ApplicationContext对象在构造函数执行时会创建一些BeanFactoryPostProcessor,比如 AnnotationConfigEmbeddedWebApplicationContext构造函数中最终会通过 AnnotationConfigUtils注册进来一些BeanFactoryPostProcessor/BeanPostProcessor

2.ApplicationContext的ApplicationContextInitializer被执行时会创建特定功能的BeanFactoryPostProcessor记录在ApplicationContext中(注意:这里不是注册到容器中,而是记录为ApplicationContext的属性);

3.ApplicationContext.refresh()中,BeanFactory prepare 和 post process 之后,会调用 invokeBeanFactoryPostProcessors() 执行这些BeanFactoryPostProcessor完成指定的功能。
详细介绍
https://www.yuque.com/docs/share/47d3ff31-74ce-470e-9280-652e60f6633f?#

2.注册 BeanPostProcessor


详细介绍
https://www.yuque.com/docs/share/47d3ff31-74ce-470e-9280-652e60f6633f?#



AbstractBeanFactory





AbstractAutowireCapableBeanFactory

综合了AbstractBeanFactory并对接口Autowired Capable BeanFactory 进行实现.

自动装箱能干的bean工厂

实例化bean和依赖注入是在AbstractBeanFactory的入口,但是实际还是在AbstractAutowireCapableBeanFactory这个类中实现。bean实例化的时候有两种基本的方式,就是一用默认构造函数,一是在xml配置自己的可带参数的构造函数,这两种方式在spring中实例的流程是不一样的,对应的BeanDefinition的数据也是不同。所以这里就根据这两种实例化的方式来讲解这个至关重要的AbstractAutowireCapableBeanFactor类。
默认构造函数实例化的方式

ApplicationContextAware

可以获得ApplicationContext及其中的bean,当需要在代码中动态获取bean时,可以通过实现这个接口来实现。




DisposableBean


用于在bean被销毁前执行特定的逻辑,例如做一些回收工作等。


ApplicationListener


用来监听spring的标准应用事件或者自定义事件。


Bean


(二)扩展点

1.Aware 接口


若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
Spring 中提供的 Aware 接口有:
1. BeanNameAware:注入当前 bean 对应 beanName;
2. BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader;
3. BeanFactoryAware:注入 当前BeanFactory容器 的引用。

// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);

}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}


以上是针对 BeanFactory 类型的容器,而对于 ApplicationContext 类型的容器,也提供了 Aware 接口,只不过这些 Aware 接口的注入实现,是通过 BeanPostProcessor 的方式注入的,但其作用仍是注入依赖。
1. EnvironmentAware:注入 Enviroment,一般用于获取配置属性;
2. EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于参数解析;
3. ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。

// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}

if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}

if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}

if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}

if (bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}

if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}

}


2.BeanPostProcessor


BeanPostProcessor 是 Spring 为修改 bean提供的强大扩展点,其可作用于容器中所有 bean,其定义如下:

public interface BeanPostProcessor {

// 初始化前置处理
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

// 初始化后置处理
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

}


常用场景有:
1. 对于标记接口的实现类,进行自定义处理。例如3.1节中所说的ApplicationContextAwareProcessor,为其注入相应依赖;再举个例子,自定义对实现解密接口的类,将对其属性进行解密处理;
2. 为当前对象提供代理实现。例如 Spring AOP 功能,生成对象的代理类,然后返回。

// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理类
return proxy;
}

return null;
}

3. init-method





init-method 是 Spring 为 bean 初始化提供的扩展点。


指定 init-method 方法,指定初始化方法:

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>





DisposableBean 和 destory-method 与上述类似,就不描述了。


(三)Bean的生命周期2 [有时间整理一下]

1.BeanNameAware


这个接口表面上的作用就是让实现这个接口的bean知道自己在spring容器里的名字,而且听官方的意思是这个接口更多的使用在spring的框架代码中,实际开发环境应该不建议使用,因为spring认为bean的名字与bean的联系并不是很深,(的确,抛开spring API而言,我们如果获取了该bean的名字,其实意义不是很大,我们没有获取该bean的class,只有该bean的名字,我们也无从下手,相反,因为bean的名称在spring容器中可能是该bean的唯一标识,也就是说再beanDefinitionMap中,key值就是这个name,spring可以根据这个key值获取该bean的所有特性)所以spring说这个不是非必要的依赖

2.BeanFacoryAware

作用:让Bean获取配置他们的BeanFactory的引用。
这个方法可能是在根据某个配置文件创建了一个新工厂之后,Spring才调用这个方法,并把BeanFactory注入到Bean中。让bean获取配置自己的工厂之后,当然可以在Bean中使用这个工厂的getBean()方法,但是,实际上非常不推荐这样做,因为结果是进一步加大Bean与Spring的耦合,而且,能通过DI注入进来的尽量通过DI来注入。
当然,除了查找bean,BeanFactory可以提供大量其他的功能,例如销毁singleton模式的Bean。
factory.preInstantiateSingletons();方法。preInstantiateSingletons()方法立即实例化所有的Bean实例,有必要对这个方法和Spring加载bean的机制做个简单说明。
方法本身的目的是让Spring立即处理工厂中所有Bean的定义,并且将这些Bean全部实例化。因为Spring默认实例化Bean的情况下,采用的是lazy机制,换言之,如果不通过getBean()方法(BeanFactory或者ApplicationContext的方法)获取Bean的话,那么为了节省内存将不实例话Bean,只有在Bean被调用的时候才实例化他们。

总结:1 实现BeanFacoryAware接口,是在Bean实例化后开始调用,在Setter方法之前调用。2 实现了BeanFacoryAware接口,可以使得bean获取到容器的内部信息,从而进行某些定制化的操作。

3.ApplicationContextAware


当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。

参考:
https://www.jianshu.com/p/4c0723615a52






ConfigurationClassPostProcessor

这个类是对BeanDefinition对象进行增删改查的,会实现BeanDefinitionRegistryPostProcessor接口.




解析@import注解 @ComponentScan @Bean注解的
主要是在org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions内部调用
org.springframework.context.annotation.ConfigurationClassUtils#checkConfigurationClassCandidate,然后拿到metadata对象,然后调用
org.springframework.context.annotation.ConfigurationClassUtils#isFullConfigurationCandidate 判断这个metadata对象是否有@Configurable注解,如果没有的话,再调用org.springframework.context.annotation.ConfigurationClassUtils#isLiteConfigurationCandidate判断这个metadata对象是否有candidateIndicators容器里面的注解,candidateIndicators容器里面有@Component和@ComponentScan和@Import和@ImportResource这四个注解.
如果还没有的话就接着检查这个metadata对象里面是否有@Bean注解.

然后这些有以上任意一个注解的类判断是否有@Order注解,
在org.springframework.context.annotation.ConfigurationClassUtils#getOrder(org.springframework.core.type.AnnotationMetadata)检查

如果有这个注解就给这个BeanDefinition设置order标识(就是打个标记,说明这个BeanDefinition有@Order注解),框架就会就会根据这个标识来决定是否排序.

包装成BeanDefinitionHolder对象,
然后在下面对configCandidates里面的BeanDefinitionHolder对象进行排序


在哪里注册的ConfigurationClassPostProcessor?

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)构造方法里面调用
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry),在这里面将ConfigurationClassPostProcessor变成BeanDefinition(就注册到Spring容器里面了.)