Spring Bean的创建过程:

Spring容器获取Bean和创建Bean都会调用getBean()方法。

getBean()方法

1)getBean()方法内部最终调用doGetBean()方法;

2)transformedBeanName(name);  返回实际的bean名称,删除工厂的取消引用:&;

3)getSingleton(beanName); 从缓存(singletonObjects)中获取,若存在则返回;

4)若缓存中不存在则获取父容器并判断BeanDefinition是否存在于父容器,如果还是找不到则沿着容器的继承体系向父级容器查找;

5)getMergedLocalBeanDefinition(beanName);获取Bean的父子BeanDefinition合并定义,并校验是否为抽象类;

6)确保当前bean依赖的bean的初始化;从Bean中获取依赖的Bean(DependsOn),若存在,则先创建依赖的Bean,创建方式即当前过程getBean();

7)创建singletion实例对象,调用getSingleton()->createBean(),在创建前后会修改各种容器中的值,防止重复创建或冲突等情况;

8)创建prototype实例对象,调用createBean(),在创建前后会修改各种容器中的值,防止重复创建或冲突等情况;

9)创建其他scope(request,session)。创建时会在request中或session中获取,获取不到调用createBean(),在创建前后会修改各种容器中的值,防止重复创建或冲突等情况;

createBean()方法

1)解析bean对应的Class;

2)验证methodOverride对应的方法是否存在?是否有重载?

3)执行InstantiationAwareBeanPostProcessor的applyBeanPostProcessorsBeforeInstantiation尝试生成bean;

4)如果没有生成,则调用 doCreateBean(beanName, bd, args);创建bean

 doCreateBean()方法

1)如果BeanDefinition 是单列,取出并清空出缓存

2)实例化:调用createBeanInstance(beanName, mbd, args);

1)解析class,先检查是否有类的访问权限,如果没有权限,抛异常;

2)检查是否有Supplier回调,如果有回调,则执行回调创建实例;

3)检查是否有工厂方法回调,如果有回调,则执行工厂方法回调创建实例;

4)如果都没有回调,则开始自己创建实例。检查缓存是否有解析的构造方法或工厂方法,如果有,再根据缓存选择无参构造(instantiateBean)还是有参构造函数(autowireConstructor)来创建实例;

5)如果缓存没有则执行determineConstructorsFromBeanPostProcessors来解析,最后根据解析结果选择无参构造还是有参构造函数来创建实例;

3)创建后,MergedBeanDefinitionPostProcessor进行合并bean的定义信息后置处理,这个MergedBeanDefinitionPostProcessor包括AutowiredAnnotationBeanPostProcessor等。

4)提前暴露bean,循环依赖处理,并将创建bean实例的ObjectFactory放入工厂缓存(singletonFactories)

5)populateBean属性赋值

1)判断是否有属性需要赋值

2)InstantiationAwareBeanPostProcessors -> postProcessAfterInstantiation 实例化之后的后置处理

3)根据名称或类型,获取需要注入的Bean

4)InstantiationAwareBeanPostProcessor -> postProcessProperties 实例化完成,对属性验证属性

5)筛选属性描述符以进行依赖检查

6)属性赋值

6)赋值后,调用initializeBean方法初始化bean

1)Aware处理,如果实现了Aware接口,会注入属性给这些bean

2)调用BeanPostProcessor -> postProcessBeforeInitialization(bean初始化回调(如InitializingBean 或自定义init-method)之前)

3)调用invokeInitMethods方法,如果实现了InitializingBean 接口,就调用他的afterPropertiesSet方法,如果有自定义方法,就继续调用自定义方法。

4)调用BeanPostProcessor -> postProcessBeforeInitialization(bean初始化回调(如InitializingBean 或自定义init-method)之后)

7)检查早期单例暴露,循环依赖检查,判断是否需要抛出异常

8)根据scope注册bean

至此,Bean创建流程完成!

Spring AOP过程:

@EnableAspectJAutoProxy注解开启 Spring AOP。

@EnableAspectJAutoProxy注解接口内部有@Import(AspectJAutoProxyRegistrar.class);

AspectJAutoProxyRegistrar.class实现ImportBeanDefinitionRegistrar接口,目的将AnnotationAwareAspectJAutoProxyCreator后置处理器的BeanDefinition注入到IOC容器当中。

AnnotationAwareAspectJAutoProxyCreator通过层层继承而实现了BeanPostProcessor接口,所以AnnotationAwareAspectJAutoProxyCreatorBeanPostProcessor。

注册时机

  1. refresh()

  2. invokeBeanFactoryPostProcessors(beanFactory);

  3. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())

  4. 实现PriorityOrderedinvokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry)

触发时机

  1. refresh()

  2. finishBeanFactoryInitialization(beanFactory);

  3. beanFactory.preInstantiateSingletons();

  4. getBean(beanName);

  5. doGetBean(name, null, null, false);

  6. createBean(beanName, mbd, args);

  7. doCreateBean(beanName, mbdToUse, args);

    1. createBeanInstance(beanName, mbd, args);//创建实例

    2. populateBean(beanName, mbd, instanceWrapper);//属性赋值

    3. initializeBean(beanName, exposedObject, mbd);//初始化

      1. applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

      2. invokeInitMethods(beanName, wrappedBean, mbd);

      3. applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

          •  wrapIfNecessary(bean, beanName, cacheKey); Spring AOP就在这一步进行创建代理并织入增强方法!

代理创建具体流程:

wrapIfNecessary()方法下:

  1.   getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); //遍历IOC容器寻找并解析@Aspect注解标注的Bean, 获取匹配当前Bean的 advisor链 (切入点和通知)
  2.   createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//创建代理类
  3.   proxyFactory.getProxy(getProxyClassLoader());
  4.   createAopProxy().getProxy(classLoader);
  5.   createAopProxy(AdvisedSupport config);//判断是创建JDK代理类还是Cglib代理类,此时会返回ObjenesisCglibAopProxy工厂类或者JdkDynamicAopProxy工厂类
  • 判断Optimize:是否使用激进优化策略,仅用于Cglib
  • 判断ProxyTargetClass:目标类本身是否是代理类而不是接口
  • 判断是否存在代理接口;

    如果以上三条都不满足直接使用JDK代理;如果满足其中一条,则再判断Target目标类是否实现了接口或者是否已经实现了jdk代理,如果是则使用JDK代理,不是则使用Cglib代理;

  JDK代理的getProx()方法:JDK动态代理机制,当调用代理类的对应方法时,代理类实际上是通过invoke()方法来完成目标类方法的调用,并在里面进行一些代理类想做的其他的操作。

    Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);//使用JDK或者Cglib 创建代理实现类

目标方法执行流程:

  IOC容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx)

  1.   CglibAopProxy.intercept();拦截目标方法的执行
  2.   根据ProxyFactory对象获取将要执行的目标方法拦截器链;List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  3. 如果没有拦截器链,直接执行目标方法;
  4. 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 Object retVal = mi.proceed();

Spring源码理论的更多相关文章

  1. 剑指Spring源码(一)

    Spring,相信每个Java开发都用过,而且是每天都在用,那强大又神秘的IoC,AOP,让我们的开发变得越来越简单,只需要一个注解搞定一切,但是它内部到底是什么样子的呢?跟着我,一起探究Spring ...

  2. Ioc容器beanDefinition-Spring 源码系列(1)

    Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...

  3. Spring源码解析(一)开篇

    前言 Spring源码继承结构比较复杂,看过以后经常会忘记.因此,记录一下源码分析的过程,方便以后回顾.本次分析的Spring源码版本为3.2.15. 另外,一提Spring就是IOC.DI等等,我们 ...

  4. Spring源码系列(二)--bean组件的源码分析

    简介 spring-bean 组件是 Spring IoC 的核心,我们可以使用它的 beanFactory 来获取所需的对象,对象的实例化.属性装配和初始化等都可以交给 spring 来管理. 本文 ...

  5. 首发!Alibaba内部:Spring源码培训课件笔记曝光!

    本文包含的内容 Spring占有的市场 阅读源码的重要性 阅读源码困难度 课件笔记的主要内容 Spring占有的市场 先来简单说一下现在各个企业常用并与Spring相关的: ssh = spring ...

  6. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  7. spring源码:学习线索(li)

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  8. spring源码:web容器启动(li)

    web项目中可以集成spring的ApplicationContext进行bean的管理,这样使用起来bean更加便捷,能够利用到很多spring的特性.我们比较常用的web容器有jetty,tomc ...

  9. spring源码解析——spring源码导入eclipse

    一.前言     众所周知,spring的强大之处.几乎所有的企业级开发中,都使用了spring了.在日常的开发中,我们是否只知道spring的配置,以及简单的使用场景.对其实现的代码没有进行深入的了 ...

随机推荐

  1. redis6安装 centos系统

    Redis6 安装   在centos7.5服务器上按照官方发布的安装方式并不能进行正确的安装,现收集并整理如下安装方式,亲测有效 1.安装依赖 yum install -y cpp binutils ...

  2. centos下安装mongodb 通过shell脚本

      #! /bin/bash yum -y update echo -e "开始安装mongodb\n" download_url=https://fastdl.mongodb.o ...

  3. pycharm2018.1下载激活(mac平台)

    此教程实时更新,请放心使用:如果有新版本出现猪哥都会第一时间尝试激活: pycharm官网下载地址:http://www.jetbrains.com/pycharm/download/ 激活前准备工作 ...

  4. Python可迭代对象和迭代器对象

    可迭代对象iterable: 对象字面意思:Python中一切皆对象.一个实实在在存在的值. 可迭代:更新迭代.迭代是一个重复的过程,每次重复是基于上一次的结果而继续的,每次都有新的内容. 可迭代对象 ...

  5. Python之format字符串格式化

    1.字符串连接 >>> a = 'My name is ' + 'Suen' >>> a 'My name is Suen' >>> a = 'M ...

  6. JavaSE学习笔记01注释、标识符与基本类型

    1. HelloWorld 编写代码 public class Hello{ public static void main(String[] args){ System.out.println(&q ...

  7. STL: set和map的区别、联系、使用

    set是一种关联式容器,其特性如下: set以RBTree作为底层容器 所得元素的只有key(键)没有value(值) 不允许出现键重复 所有的元素都会被自动排序 不能通过迭代器来改变set的值,因为 ...

  8. 蓝桥杯2020 E:七段码

    题解 正规解法是 dfs + 并查集,首先用 dfs 将其所有的情况枚举出来,再用并查集来判断是否在一个连通块上. 许多小伙伴计算的答案为76,主要是判断连通块这方面有问题,倘若不用并查集,直接枚举一 ...

  9. 强网杯web之假的反序列化漏洞

    说明 打强网杯的时候一直在写论文, 做林逸师傅的培训题目. 现在得空,还是看了一部分的题目和wp. 源码 源码一共三部分, 这里只写下我知识盲区的一部分,作为自己的记录. <?php highl ...

  10. 使用 Filebeat 对多行日志进行处理(multiline)

    Filebeat 收集日志的过程中,默认是按行收取的,也就是每一行都会默认是一个单独的事件并添加时间戳.但是在收集一些特殊日志的时候,往往一个事件包含有多行,例如 Java 的堆栈跟踪日志: 20-0 ...