不论是采用 XML 还是注解方式,最终 Spring 读取加载后都会生成与之对应的 BeanDefinition,然后利用它就可以去实例化一个对象。
BeanDefinition 用来描述创建一个实例所需要的信息
简单的看来创建一个对象其实就 2 步骤
Spring 就在这几个步骤中穿插逻辑,从而拓展出了一个生态,下面我们就来看看 AOP 的实现原理
基本用法这里就不再赘述
在 new AnnotationConfigApplicationContext(Class<?>... componentClasses)
首先将 AppConfig
解析为 BeanDefinition
放入 BeanFactory
的 BeanDefinitionMap
中
然后调用 refresh()
方法中,会调用 invokeBeanFactoryPostProcessors(beanFactory);
在这个方法中去调用所有的 BeanFactoryProcessor
那么什么是 BeanFactoryProcessor
它又有什么作用呢?看下面这段代码
通过实现了 BeanFactoryProcessor
我们可以拿到 ConfigurableListableBeanFactory
,通过容器我们就能拿到 BeanDefinition
进行分析和修改,从而间接的影响 Bean 的实例化做到我们无感知,无侵入的增强和拓展类的功能
然后该方法中,会继续调用 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
(还调用了其它的方法,本文只讨论这个方法), BeanDefinitionRegistryPostProcessor
它的作用是可以像容器中添加新的 BeanDefinition
,在这一步将解析 JavaConfig
对应的 BeanDefinition
,然后解析 @ComponentScan(basePackages = "com.example.ana")
这个注解,将这个包下面的所有类,装载为 BeanDefinition
然后放入 BeanFactory
容器中
到此为止,包下面的所有类就已经扫描装载完毕在 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 存入代理对象中,最后容器中最后的实现类也变成了对应的代理类
在 resolveBeforeInstantiation
方法后就会调用 doCreateBean
来创建实例,在这里面首先会创建一个早期 bean 对象,这个对象主要是用于解决循环依赖问题,比如
class A { B b; } class B { A a; } 复制代码
他们都是单例,Spring 在实例化 A 的时候,发现依赖了 B 需要去实例化 B,在实例化 B 的时候又发现需要实例化 A,造成循环依赖无法实例化成功
Spring 解决这个问题的核心思想非常简单,就是先创建一个早期 A 对象,仅仅是一个没有填充属性的引用,然后去创建 B 对象的时候再填充 A 就成功了,方法递归返回 A 对象也就创建成功了,容器已经持有了对应的引用,那么在后续填充完各自的属性后就算创建完整了
上一步操作得到了一个早期的 bean 对象,并且放入了早期容器中下一步就是调用 populateBean
对 bean 的属性就行填充,主要做以下 2 件事情
如果类实现了 InitializingBean
接口,就调用它的 afterPropertiesSet
进行值的设置
如果 XML 定义了 init-method 的话后续就会调用 invokeCustomInitMethod
,然后调用对应的初始化方法进行初始化
在初始化 Bean 完成后就会调用 applyBeanPostProcessorsAfterInitialization
,旨在初始化完成后再给与一次修改 Bean 的机会
在这个方法中会去获取所有的 BeanPostProcessor
然后依次调用其 postProcessAfterInitialization
方法
除去我们自己实现了 BeanPostProcessor
之外,框架本身还提供了很多用于自身使用,这些 Processor 会在 refresh()
中的 registerBeanPostProcessors
方法中进行注册和排序
其中有一个是 AbstractAutoProxyCreator
的实现,调用它的 postProcessAfterInitialization
里面会调用 wrapIfNecessary
,这个方法首先它会去找到所有候选的 advisor
,然后判断当前类或者实例中的方法,是否满足 @PointCut
的表达式,将成功匹配到的 advisor
返回
advisor
设置进去
到此为止一个完整的代理对象就创建完毕