Visão geral
Vamos primeiro olhar para o diagrama de arquitetura geral da primavera
interface básica
Resource+ResourceLoader
Os arquivos de configuração que escrevemos na forma de xml ou anotações são todos Resource
recursos na visualização do spring, e o spring também fornece um ResourceLoader
para carregar os recursos que escrevemos
BeanFactory
Vamos primeiro dar uma olhada no relacionamento de herança do beanfactory.A interface do beanFactory define alguns métodos básicos para obter beans, nada de especial.A seguir ver as três interfaces abaixo do bean
- HierarchicalBeanFactory
Apenas defina o relacionamento pai-filho do beanFactory 2. A interface definida na documentação oficial do ListableBeanFactory foi projetada para permitir que as pessoas percorram melhor os beans no contêiner, então também podemos ver que a interface recém-adicionada retorna um array de nomes de bean
DefaultListableBeanFactory
Depois de olhar para a subinterface de BeanFactory acima, vamos olhar para uma classe de implementação. Vamos primeiro olhar para a GenericApplicationContext
classe . Essa classe é a classe pai do nosso contêiner IOC comumente usado. Podemos ver que há uma variável de membro nesta classe .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 classe é do spring 信息中心,包含所有bean的定义信息
, mas o container ioc que ele usa conosco não é um relacionamento de herança e sim um relacionamento de combinação
BeanDefinition
BeanDefinition descreve uma instância de um bean, que pode obter propriedades como o nome do bean, escopo, se ele é carregado lentamente e assim por diante.
BeanDefinitionRegistro
Um registro BeanDefinition, que contém o relacionamento de mapeamento 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
O processo de inicialização é o seguinte postProcessBeforeInitialization
: O método é executado antes que o método de inicialização seja chamado, para que o usuário possa 不断的包装对象
, se retornar null, o loop é encerrado. Após o retorno , o método de inicialização é executado. InitializingBean
O método é acionado aqui. Depois que o método de inicialização for executado postProcessBeforeInitialization
, o spring chamará Outro método de ciclo de vida que também permite que os usuários envolvam várias camadas