Visión de conjunto
Veamos primero el diagrama de arquitectura general de Spring.
interfaz básica
Recurso+Cargador de recursos
Los archivos de configuración que escribimos en forma de xml o anotaciones son todos Resource
recursos en la vista de Spring, y Spring también proporciona uno ResourceLoader
para cargar los recursos que escribimos.
BeanFactory
Primero echemos un vistazo a la relación de herencia de beanfactory. La interfaz de beanFactory define algunos métodos básicos para obtener beans, nada especial. A continuación las tres interfaces debajo del bean.
- HierarchicalBeanFactory
Simplemente defina la relación padre-hijo de beanFactory 2. La interfaz definida en la documentación oficial de ListableBeanFactory está diseñada para permitir a las personas recorrer mejor los beans en el contenedor, por lo que también podemos ver que la interfaz recién agregada devuelve una matriz de nombres de beans
DefaultListableBeanFactory
Después de ver la subinterfaz de BeanFactory arriba, veamos una clase de implementación. Primero veamos la GenericApplicationContext
clase . Esta clase es la clase principal de nuestro contenedor IOC de uso común. Podemos ver que hay una variable miembro en esta clase . .DefaultListableBeanFactory
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
bean的名称映射
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
根据类型和名称的映射
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
只有单利的类和名称映射
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
获得所有bean信息
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
复制代码
Esta clase es de spring 信息中心,包含所有bean的定义信息
, pero el contenedor ioc que usa con nosotros no es una relación de herencia sino una relación de combinación.
BeanDefinición
BeanDefinition describe una instancia de un bean, que puede obtener propiedades como el nombre del bean, el alcance, si tiene carga diferida, etc.
BeanDefinitionRegistro
Un registro BeanDefinition, que contiene la relación de mapeo de BeanDefinition
ApplicationContext
包含了很多功能,从继承接口可以看出,包含了ioc事件派发器,国际化解析,bean工厂,资源解析功能
Aware
在spring中有非常多的XXXAware,用了之后就可以获得到对象实例
BeanDefinition信息注册到BeanDefinitionRegistry流程
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Cat bean = context.getBean(Cat.class);
System.out.println(bean);
}
复制代码
代码很简单,现在来debug看spring注册流程
- 在
ClassPathXmlApplicationContext
的构造方法里执行了refresh方法
2. refresh是 AbstractApplicationContext
的方法,又调用了obtainFreshBeanFactory
让子类刷新内部的beanFactory 3. 随后调用了 AbstractRefreshableApplicationContext
类的 refreshBeanFactory方法。我们可以看到在这里创建了一个 DefaultListableBeanFactory
,然后把该对象传入子类的loadBeanDefinition
方法 4. 来到AbstractXmlApplicationContext
类的loadBeanDefinition,根据DefaultListableBeanFactory创建了一个XMLBeanDefinitionReader
然后读取配置文件 5. XMLBeanDefinitionReader
的doLoadBeanDefinition方法中,根据配置文件生成Document对象然后读取 随后再创建了一个 BeanDefinitionDocumentDocumentReader
,调用registerBeanDefinitions方法读取数据 6. 在BeanDefinitionDocumentDocumentReader 的内部有一个代理类,解析数据其实都是该类实现的 方法内遍历每一个节点解析数据 然后解析内部就是判断xml标签走不同的方法 7. 在解析bean的方法内部先封装了一个 BeanDefinitionHolder
组合了bean的名称和BeanDefinition
,然后调用一个工具类解析数据 8. 工具类内部调用 DefaultListableBeanFactory
的 方法注册Bean信息到档案馆 9. 现在正式来到DefaultListableBeanFactory
内部,首先会判断这个beanName是否已经在BeanDefinitionMap中存在,如果不存在就添加到map里面,并且也会添加一个名字列表到数组中
创建单实例Bean流程
我们刚才看的是Bean的定义信息已经被保存到spring中,我们现在来看看Spring创建实体对象的流程。
- 还是
AbstractApplicationContext
类的refresh方法,方法走到了finishBeanFactoryInitialization
方法,该方法主要设置了一些beanFactory的一些参数然后调用preInstanceSingletons
方法
2. 这个beanFactory就是那个DefaultListableBeanFactory
,方法中通过遍历之前已经初始化好的BeanDefinitionNames,创建不是抽象,是单例,不是懒加载的对象 3. 方法来到了父类AbstractBeanFactory
中的doGetBean
方法中,这个方法有很多逻辑,我们先来看首次创建的逻辑 4. 做了上面一系列判断之后,调用父类DefaultSingletonBeanRegistry
的getSingleton方法,方法中还会有一个回调,先不看父类的方法逻辑,直接看回调方法的createBean
,这是一个抽象方法,由子类AbstractAutowireCapableBeanFactory
实现 5. 执行一些暂时无意义的方法之后来到了instantiateBean
方法,内部有一个创建bean的策略类,实现有jdk的反射和cglib 6. spring在创建bean的过程中会判断该对象是否有重写的方法,如果有的话就走gclib,没有就走jdk默认
Bean属性赋值过程
我们上面看完了Bean实例的创建过程再来看一下Bean内部的属性是如何被spring注入进来的。在AbstractAutowireCapableBeanFactory
的doCreateBean方法中创建完bean实例之后继续往下执行
- 在doCreateBean方法内部,实例化bean后调用
populateBean
方法给bean属性赋值
2. 在populateBean方法中,如果是注解的方式启动的spring则会走后置处理器的方式来赋值对象,如果是xml的形式则会走另一个方法,现在大部分都是注解的方式启动的容器,所以我们直接看后置处理器的方式 3. 在初始化完bean之后spring会执行容器中的所有InstantiationAwareBeanPostProcessor
对象的postProcessProperties方法,在方法中获得一个InjectionMetadata
对象,该对象就有需要注入的对象和方法,后面就是直接调用invoke方法就可以了。 4. 我们再来看看spring是如何寻找@Autowire
注解的,在上面方法的第一行的方法findAutowiringMetadata
进去 可以看到其实返回的数据是调用buildAutowiringMetadata
方法 该方法是从目标类一直循环上去,找属性是不是有目标注解 遍历集合判断是否有数据 数据的初始化就是添加这些注解
spring的后置处理器
spring提供了三种后置处理器
BeanFactoryPostProcessor
BeanPostProcessor
InitializingBean
我们来依次看每个后置处理器的执行流程。
BeanFactoryPostProcessor
首先还是回到refresh方法中,我们可以看到在创建普通bean对象的上面有个方法叫invokeBeanFactoryPostProcessor,从方法名就可以看出是执行BeanFactoryPostProcessor方法 方法内部调用了一个代理类的静态方法 方法内部会首先拿出实现了PriorityOrdered
接口的对象排序后执行
执行完PriorityOrdered
接口后再拿出实现了Order
接口的对象执行 最后把剩下的BeanFactoryPostProcessor根据类名排序后调用方法,这时候容器里面还是没有对象的,在getBean的时候需要走原来看过的创建普通bean的流程 前面的都是执行的BeanDefinitionRegistryPostProcessor
的方法postProcessBeanDefinitionRegistry
,三个判断结束之后最后执行BeanFactoryPostProcessor
的postProcessBeanFactory
方法 流程图如下
工厂后置增强的实际用途
我们现在知道了spring提供了一些工厂的后置处理器来增强工厂,那么我们现在来看看spring中实际使用工厂后置处理器做了什么事情,我们来看一个类ConfigurationClassPostProcessor
这个类是用于处理写了@Configuratioin
注解的类 排序好之后就在一个循环里面解析容器里面的类 在方法中先判断是不是需要跳过,如果写了@Conditional
注解的对象会判断条件是否生效 真正解析配置类的方法里面就是各种判断注解的情况,然后去做相应的方法
BeanPostProcessor 注册
工厂的增强至此就结束了,接下来看看普通组件的后置处理器的逻辑,还是回到refresh方法,这次是调用registerBeanPostProcessors
方法,注册后置处理器。 注册的逻辑跟BeanFactory都是由同一个代理类来完成的 大部分逻辑和bean工厂的逻辑一致,都是判断优先级接口的就先执行 跟bean工厂不一致的是,bean工厂的后置处理器直接执行目标方法,这里只是把bean后置处理器创建好之后就放入list中
InstantiationAwareBeanPostProcessor
所有的BeanPostProcessor都被注册之后,我们来看其中一个分支:InstantiationAwareBeanPostProcessor
的流程
SmartInstantiationAwareBeanPostProcessor
从名字上可以看出叫智能的
实例后置处理器,那么这个我们就来看看智能在什么地方. 在refresh方法中调用了一个注册监听器的方法 在该方法中调用了一个根据类型获取名称列表
的方法,该方法是ListableBeanFactory
接口的一个方法 为了获得目标类的名称,spring遍历所有的bean的名称,一个一个判断
判断逻辑是先判断已经初始化好的实例,然后再判断bean定义信息,如果都没有则让别人来判断 拿到容器中的SmartInstantiationAwareBeanPostProcessor然后把类名和bean名称穿进去,让实现类来决定 总结流程图 所以我们知道,在spring中,根据类型来找名称其实spring需要遍历所有对象,是一件很麻烦的事情
InstantiationAwareBeanPostProcessor
在spring容器创建对象之前,会先调用 InstantiationAwareBeanPostProcessor的 postProcessBeforeInstantiation
方法尝试返回对象,如果用户返回了则会用用户创建的对象。 如果没有则调用doCreateBean方法,方法内也会从一个缓存中获取,没有的话就继续调用方法创建 创建逻辑会让用户返回一个构造函数,注意这里调用的是SmartInstantiationAwareBeanPostProcessor的一个方法,如果没有就用默认的无参构造函数,之后就是上面写过的用工具类创建的方式
MergedBeanDefinitionPostProcessor
在创建好bean实例对象之后会调用一下MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法让用户定义一下BeanDefinition
PopulateBean
之后就进入属性赋值方法,首先会先执行 InstantiationAwareBeanPostProcessor
的 postProcessAfterInstantiation方法,返回bool类型的值,如果返回true则会继续属性赋值,返回false则不会属性赋值 如果返回true则开始执行InstantiationAwareBeanPostProcessor
的 postProcessProperties方法。自动注入 AutowiredAnnotationBeanPostProcessor
的该方法就实现了自动注入的属性赋值
PropertyValues
在上面我们可以看到postProcessProperties方法返回了一个pvs,我们也可以自定义返回pvs,spring最后会帮我们注入到对象中,创建一个PVS返回即可
BeanPostProcessor
属性赋值之后spring会执行initializeBean
方法初始化bean,首先会先执行一些 Aware
的注入
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
El proceso de inicialización es el siguiente postProcessBeforeInitialization
: el método se ejecuta antes de que se llame al método de inicialización, de modo que el usuario pueda 不断的包装对象
, si uno devuelve nulo, entonces el ciclo finaliza. Después de que se devuelve , se ejecuta el método de inicialización. InitializingBean
El método es Desencadenado aquí Después de ejecutar postProcessBeforeInitialization
, Spring llamará a Otro método de ciclo de vida que también permite a los usuarios envolver varias capas.