不管是采用 XML 仍是注解方式,最终 Spring 读取加载后都会生成与之对应的 BeanDefinition,而后利用它就能够去实例化一个对象。java
BeanDefinition 用来描述建立一个实例所须要的信息express
简单的看来建立一个对象其实就 2 步骤缓存
Spring 就在这几个步骤中穿插逻辑,从而拓展出了一个生态,下面咱们就来看看 AOP 的实现原理app
基本用法这里就再也不赘述框架
在 new AnnotationConfigApplicationContext(Class<?>... componentClasses)
首先将 AppConfig
解析为 BeanDefinition
放入 BeanFactory
的 BeanDefinitionMap
中post
而后调用 refresh()
方法中,会调用 invokeBeanFactoryPostProcessors(beanFactory);
在这个方法中去调用全部的 BeanFactoryProcessor
spa
那么什么是 BeanFactoryProcessor
它又有什么做用呢?看下面这段代码代理
经过实现了 BeanFactoryProcessor
咱们能够拿到 ConfigurableListableBeanFactory
,经过容器咱们就能拿到 BeanDefinition
进行分析和修改,从而间接的影响 Bean 的实例化作到咱们无感知,无侵入的加强和拓展类的功能code
而后该方法中,会继续调用 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
(还调用了其它的方法,本文只讨论这个方法),BeanDefinitionRegistryPostProcessor
它的做用是能够像容器中添加新的 BeanDefinition
,在这一步将解析 JavaConfig
对应的 BeanDefinition
,而后解析 @ComponentScan(basePackages = "com.example.ana")
这个注解,将这个包下面的全部类,装载为 BeanDefinition
而后放入 BeanFactory
容器中component
到此为止,包下面的全部类就已经扫描装载完毕在 BeanFactory
的 BeanDefinitionMap
中
要想应用 advice 逻辑,首先咱们须要找到对应的切面,而后咱们在其中查看须要在哪些方法中织入对应的 advice 逻辑,好比在 UserServiceImpl
的 queryUser
这个 JoinPoint
切点以后织入 afterQuery
这分为 2 步,先来看是如何查找切面 @Aspect
的,从 refresh()
中看起走,到这个位置
在 createBean 中调用了 resolveBeforeInstantiation
这个方法,目的就是给 BeanPostProcessor
一个返回代理对象的机会,好比下图将全部 beanName 名字为 a 的对象替换成对象 C
它有它的做用好比
咱们这里是为了寻找对应的 @Aspect
接着往下看,获取全部的 BeanPostProcessor
须要注意的是除去咱们本身定义的 BeanPostProcessor
以外还有框架自身的一些实现类,而后若是发现类是 InstantiationAwareBeanPostProcessor
的话
@Aspect
这个注解advice
的相关信息缓存到 advisorsCache
中首次调用 BeanPostProcessor
的实现就会作以上这件事,后续的调用就直接从缓存中取用便可
如今全部的 @Aspect
都已经缓存好了,如今就要知道如何在调动业务逻辑的时候,如何织入对应的 advice 逻辑,好比在调用一个事务方法的时候,系统是怎么帮我作到,自动打开事务,方法结束的时候提交事务的,这就须要一个代理对象帮我去作这件事情,那么何时该建立代理对象,代理对象又是如何执行对应的 advice 方法呢
举个很简单的例子
User user = new User("小李");
user.getName();
复制代码
这里就只有一个获取名称的方法,其它什么都不须要,那你说还须要为它建立代理对象吗,确定不须要,再看下面这个
@Transactional
public void saveXXX() {
xxxDao.saveUser();
xxxDao.saveProject();
}
复制代码
这个方法咱们添加了事务,要求只要其中一个失败就得进行回滚从而保证这个操做是一个原子操做,这个方法确定就须要建立代理对象了
就这个例子来看,当咱们发现所调用方法的注解具备必定的逻辑功能的话就须要建立代理对象,拓展来看就是说,咱们须要判断一个类,或者类中是否存在某个方法须要被加强处理,从而来决定是否建立代理对象
那么在咱们这个例子中,在实例化每一个对象的时候,就是首先从 advisorsCache
取出 advisor
检测当前类是否知足 pointcut
的 expression
条件,知足的话就须要为其建立代理对象,而且将匹配到的 advisor 存入代理对象中,最后容器中最后的实现类也变成了对应的代理类
1) 早期 bean 对象的建立
在 resolveBeforeInstantiation
方法后就会调用 doCreateBean
来建立实例,在这里面首先会建立一个早期 bean 对象,这个对象主要是用于解决循环依赖问题,好比
class A {
B b;
}
class B {
A a;
}
复制代码
他们都是单例,Spring 在实例化 A 的时候,发现依赖了 B 须要去实例化 B,在实例化 B 的时候又发现须要实例化 A,形成循环依赖没法实例化成功
Spring 解决这个问题的核心思想很是简单,就是先建立一个早期 A 对象,仅仅是一个没有填充属性的引用,而后去建立 B 对象的时候再填充 A 就成功了,方法递归返回 A 对象也就建立成功了,容器已经持有了对应的引用,那么在后续填充完各自的属性后就算建立完整了
2)填充 Bean 的相关属性
上一步操做获得了一个早期的 bean 对象,而且放入了早期容器中下一步就是调用 populateBean
对 bean 的属性就行填充,主要作如下 2 件事情
3)初始化 Bean
若是类实现了 InitializingBean
接口,就调用它的 afterPropertiesSet
进行值的设置
若是 XML 定义了 init-method 的话后续就会调用 invokeCustomInitMethod
,而后调用对应的初始化方法进行初始化
4)建立代理实例
在初始化 Bean 完成后就会调用 applyBeanPostProcessorsAfterInitialization
,旨在初始化完成后再给与一次修改 Bean 的机会
在这个方法中会去获取全部的 BeanPostProcessor
而后依次调用其 postProcessAfterInitialization
方法
除去咱们本身实现了 BeanPostProcessor
以外,框架自己还提供了不少用于自身使用,这些 Processor 会在 refresh()
中的 registerBeanPostProcessors
方法中进行注册和排序
其中有一个是 AbstractAutoProxyCreator
的实现,调用它的 postProcessAfterInitialization
里面会调用 wrapIfNecessary
,这个方法首先它会去找到全部候选的 advisor
,而后判断当前类或者实例中的方法,是否知足 @PointCut
的表达式,将成功匹配到的 advisor
返回
advisor
设置进去
到此为止一个完整的代理对象就建立完毕
advice
方法做为一个调用链 chain
CglibMethodInvocation
而后调用 proceed
advice
方法和执行被代理的目标方法总的来讲就分为 2 步骤