Spring思维导图
SpringAOP切面解析流程图
SpringAOP创建代理流程图
AOP (Aspect Oriented Programming)
AOP 面向切面编程,要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理。AOP 的实现并不是因为 Java 提供了神奇的钩子,可以把方法的几个生命周期告诉我们,而是我们要实现一个代理,实际运行的实例其实是生成的代理类的实例。
AOP 术语解释
- 切面(Aspect): 在 AOP 中指切面类 (通常被 @Aspect 标注),管理着通知和切点
- 连接点(Join Point): 切面和被增强方法所连接的点(即代理方法,我们需要增强的方法)
- 通知(Advice): 某个特点的连接点上执行的动作,通常包括 前置(Before),后置(After),异常(Exeception),环绕(Around)
- 目标对象(Target): 需要被增强的对象,即包含业务逻辑类的对象
- 切点(PointCut): 匹配连接点的断言,由其决定哪些方法需要被增强,哪些不需要被增强,是AOP核心。Spring 默认使用 AspectJ 切点语义
- 顾问(Advisor): 通知 (Advice) 的一种包装体现。是 Advice 和 PointCut 的结合,无需应用关心
- 织入(Weaving): 将通知切入连接点的过程
- 引入(Introductions): 将其他接口和实现动态的引入targetClass中,不常用
AspectJ
AspectJ 是 AOP 编程的完全解决方案,它能做许多AOP实现不了的事情。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入)。
SpringAOP中的 @Aspect、@PointCut、@Before、@After、@Around 都来自 AspectJ,但功能都有 SpringAOP自己实现
SpringAOP
-
它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现
1、如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP,可以强制使用 CGLIB 实现
2、如果目标对象没有实现了接口,必须采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 之间转换 -
Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,不需要显式引入依赖
-
Spring AOP 需要依赖于 IOC 容器来管理
-
Spring AOP 只能作用于 Spring 容器中的 Bean,使用纯粹的 Java 代码实现的,只能作用于 Bean 的方法
-
Spring 提供了 AspectJ 的支持,但只用到的AspectJ的切点解析和匹配
Spring AOP 的配置方式
Spring AOP 一共有三种配置方式,并且做到了很好的向下兼容
- Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的,Spring 的事务就是此方式实现的
- Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用命名空间
- Spring 2.0 @AspectJ配置:使用注解的方式来配置
@EnableAspectJAutoProxy
基于接口:
首先定义需要被增强的类:
接口:Calculate.java
实现类:TestCalculate.java
// 接口
public interface Calculate {
/** 加 **/
int add(int numA, int numB);
/** 减 **/
int sub(int numA, int numB);
/** 乘 **/
int multi(int numA, int numB);
/** 除 **/
int div(int numA, int numB);
}
// 实现类,将该类交给 Spring 管理才能动态代理实现AOP
public int add(int numA, int numB) {
System.out.println("Invoke Method:add");
System.out.println(1/0); // 测试异常
return numA+numB;
}
public int sub(int numA, int numB) {
System.out.println("Invoke Method:reduce");
return numA-numB;
}
public int div(int numA, int numB) {
System.out.println("Invoke Method:div");
return numA/numB;
}
public int multi(int numA, int numB) {
System.out.println("Invoke Method:multi");
return numA*numB;
}
第二步:配置 advice 或 Interceptor
// Advice 通知
public class TestLogAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String methodName = method.getName();
System.out.println("invoke method " + methodName + "() <BeforeAdvice>,args" + Arrays.asList(args));
}
}
// Interceptor 拦截器
public class TestLogInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(getClass()+"Before Invoke");
Object ret=invocation.proceed();
System.out.println(getClass()+"After Invoke");
return ret;
}
}
最后配置配置类:
// 被代理对象
@Bean
public Calculate testCalculate() {
return new TestCalculate();
}
// Advice 方式
@Bean
public TestLogAdvice testLogAdvice(){
return new TestLogAdvice();
}
// Interceptor 类似环绕通知
@Bean
public TestLogInterceptor testLogInterceptor() {
return new TestLogInterceptor();
}
/**
* FactoryBean方式单个: ProxyFactoryBean
* 只能指定单一的Bean的AOP
* 拦截器的粒度只控制到了类级别,类中所有的方法都进行了拦截
* @return
*/
@Bean
public ProxyFactoryBean calculateProxy(){
ProxyFactoryBean userService=new ProxyFactoryBean();
userService.setInterceptorNames("testLogAdvice","testLogInterceptor"); // 根据指定的顺序执行
userService.setTarget(testCalculate());
return userService;
}
测试类与运行结果:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class);
Calculate calculateProxy = ctx.getBean("calculateProxy",Calculate.class);
calculateProxy.div(1,1);
}
--------------------执行结果--------------------
invoke method div() <BeforeAdvice>,args[1, 1]
class zhe.hello.aop.TestLogInterceptor Before invoke Method
Invoke Method:div
class zhe.hello.aop.TestLogInterceptor After invoke Method
从结果可以看到,使用了责任链方式对 advice 和 Interceptor 都进行调用。这个例子理解起来应该非常简单,就是通过调用 FactoryBean(ProxyFactoryBean) 的 getObject() 方法创建一个代理实现。责任链的两个重要依靠:统一抽象、循环或递归。
但是这种方式存在几个指明缺点:
- 只能指定单一的 Bean 的 AOP,多个 Bean 需要创建多个 ProxyFactoryBean
- 添加一个通知我们就需要配置一个 MethodXxxxAdvice 或 MethodInterceptor 类
- 拦截器的粒度只控制到了类级别,类中所有的方法都进行了拦截
在上面的配置中,配置拦截器的时候,interceptorNames
除了指定为 Advice,是还可以指定为 Interceptor 和 Advisor 的。这里我们来理解 Advisor 的概念,它是经过包装后的细粒度控制方式,它内部需要指定一个 Advice,Advisor 决定该拦截哪些方法 (即 Advice + PointCut),拦截后需要完成的工作还是内部的 Advice 来做。
它内部有多个实现,我们以NameMatchMethodPointcutAdvisor
为例,顾名思义,就是通过提供方法的名字,复合的就进行拦截。
/**
* Advisor 种类很多:
* RegexpMethodPointcutAdvisor 按正则匹配类
* NameMatchMethodPointcutAdvisor 按方法名匹配
* DefaultBeanFactoryPointcutAdvisor xml解析的Advisor <aop:before
* InstantiationModelAwarePointcutAdvisorImpl 注解解析的advisor(@Before @After....)
*/
@Bean
public NameMatchMethodPointcutAdvisor testLogAspectAdvisor() {
NameMatchMethodPointcutAdvisor advisor=new NameMatchMethodPointcutAdvisor();
// 通知(Advice) :是通知类 没有带切点
// 通知者(Advisor):是经过包装后的细粒度控制方式 带了切点
advisor.setAdvice(testLogAdvice()); // 通知者
advisor.setMappedNames("div"); // 切点
return advisor;
}
/**
* 除此之外按正则匹配也放在这里
* 按正则匹配
*/
@Bean
public RegexpMethodPointcutAdvisor testLogAspectInterceptor() {
RegexpMethodPointcutAdvisor advisor=new RegexpMethodPointcutAdvisor();
advisor.setAdvice(testLogInterceptor()); // 通知者
advisor.setPattern("test.TestCalculate.*"); // 切点
return advisor;
}
/**
* FactoryBean方式单个: ProxyFactoryBean
* 控制粒度到方法
* 问题:只能指定单一的Bean的AOP,
* 如果多个Bean需要创建多个ProxyFactoryBean 。
**/
@Bean
public ProxyFactoryBean calculateProxy(){
ProxyFactoryBean userService = new ProxyFactoryBean();
userService.setInterceptorNames("testLogAspectAdvisor");
userService.setTarget(testCalculate());
return userService;
}
从上述代码中可以看到calculateProxy
这个 bean 配置了一个advisor
,内部还可以指定切点,设置更细粒度的控制,从方法级别继续拦截,不在局限于类。
// ProxyFactoryBean
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class);
Calculate calculateProxy = ctx.getBean("calculateProxy",Calculate.class);
System.out.println(calculateProxy.getClass());
calculateProxy.div(1,1);
--------------------执行结果--------------------
invoke method div() <BeforeAdvice>,args[1, 1]
Invoke Method:div
但是面所有的实现都存在一个共同的问题,它们都得为每个 bean 都配置一个代理,之后获取 bean 的时候需要获取这个代理类的 bean 实例(例如ctx.getBean("calculateProxy",Calculate.class)
)。那么怎么才能实现自动根据类型注入呢?下面介绍 autoproxy 的解决方案。
autoproxy:顾名思义就是实现自动代理,当 Spring 发现一个 bean 需要被切面织入的时候,Spring 会自动生成这个 bean 的一个代理来拦截方法的执行,确保定义的切面能被执行。
下面我们可以去掉原来的 ProxyFactoryBean 的配置,改为使用 BeanNameAutoProxyCreator 来配置:
/**
* autoProxy: BeanPostProcessor手动指定Advice方式 BeanNameAutoProxyCreator
**/
@Bean
public BeanNameAutoProxyCreator autoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
//设置要创建代理的那些Bean的名字
// 以test开头的类都创建代理
beanNameAutoProxyCreator.setBeanNames("test*");
//设置拦截链名字(这些拦截器是有先后顺序的)
// setInterceptorNames(String... interceptorNames) 可以设置多个
beanNameAutoProxyCreator.setInterceptorNames("testLogAspectAdvisor");
return beanNameAutoProxyCreator;
}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class);
Calculate calculateProxy = ctx.getBean("calculateProxy",Calculate.class);
System.out.println(calculateProxy.getClass());
calculateProxy.div(1,1);
calculateProxy.add(1,1);
--------------------执行结果--------------------
class com.sun.proxy.$Proxy11
invoke method div() <BeforeAdvice>,args[1, 1]
invoke method div() <BeforeAdvice>,args[1, 1]
Invoke Method:div
Invoke Method:add
从执行结果可以发现,我们在使用时已经完全不需要关心代理,直接使用原来的类型即可。例如我们使用BeanNameAutoProxyCreator
,它只需要指定被拦截类名的模式 (如 *ServiceImpl),它可以配置多次,这样就可以用来匹配不同模式的类了。
当然,我们也可以不配置BeanNameAutoProxyCreator autoProxyCreator()
直接使用下面的配置,让所有的 Advisor 自动生效。也就不需要autoProxyCreator()
的配置了
@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
到这里,已经可以看出能够十分方便的创建代理了,基于注解形式的也就是在此基础上进行改造读取切面类,及方法上的注解而已。
下面是基于注解形式的实现
切面类:
@Aspect
@Order
@Component
public class TestLogAspect {
/*引入: 不常用*/
@DeclareParents(value="cn.zhe.hello.aop.TestCalculate", // 动态实现的类
defaultImpl = SimpleProgramCalculate.class) // 引入的接口的默认实现
public static ProgramCalculate programCalculate; // 引入的接口
@Pointcut("execution(* cn.zhe.hello.aop.TestCalculate.*(..))") // 切点
public void pointCut(){};
@Before(value = "pointCut()")
public void methodBefore(JoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <Before Advice>,args"+ Arrays.asList(joinPoint.getArgs()));
}
@After(value = "pointCut()")
public void methodAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <After Advice>,args"+Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "pointCut()",returning = "result")
public void methodReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <Return Advice>,args"+Arrays.asList(joinPoint.getArgs()));
}
@AfterThrowing(value = "pointCut()")
public void methodAfterThrowing(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <Exception Advice>,args"+Arrays.asList(joinPoint.getArgs()));
}
}
测试类及运行结果:
public class TestMainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
Calculate calculate = (Calculate) ctx.getBean("testCalculate");
int retVal = calculate.div(2,4);
}
}
--------------------执行结果--------------------
Invoke Method div() <Before Advice>,args[2, 4]
Invoke Method:div
Invoke Method div() <Return Advice>,args[2, 4]
Invoke Method div() <After Advice>,args[2, 4]
SpringAOP 源码解析
相信大家都指定 Spring 中的 AOP 是通过动态代理来实现的。Spring 通过一个 @EnableAspectJAutoProxy 注解开启AOP,Spring 通过定义一个切面类 (标注@Aspect) ,并定义一个 @Pointcut 方法,最后再定义一些列的增强方法,就能完成一些列的对象切面操作。增强方法类型如下:
// @环绕通知、前置通知、后置通知、返回通知、异常通知
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
由我们上面所了解到的知识,可以推测出它大概分为以下几个步骤:
- 找到所有的切面类并解析 (解析切面类)
- 解析出所有的 Advice 并保存 (缓存通知)
- 创建一个动态代理 (JDK OR CGLIB)
- 调用被代理类的方法时,找到所有增强 (Advice),并增强方法
先来看一下整体流程图
下面我们来逐步分解源码
一、注册 Bean的后置处理器
首先 Spring 通过一个 @EnableAspectJAutoProxy 注解开启AOP,点进去我们可以发现,在注解类上面发现了另一个注解 @Import(AspectJAutoProxyRegistrar.class),该类实现了 ImportBeanDefinitionRegistrar ,所以他会通过registerBeanDefinitions()
为容器导入 BeanDefinition。
在postProcessBeforeInstantiation中解析切面逻辑将在后文解释。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented1
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {}
二、解析切面类
在我们的创建Bean调用doCreatBean()
方法之前会调用 applyBean
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
// 获取容器中所有的后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 判断后置处理器是不是InstantiationAwareBeanPostProcessor
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 把BeanPostProcessor强制转为InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/**
* @EnableAspectJAutoProxy为容器导入AnnotationAwareAspectJAutoProxyCreator
* @EnableTransactionManagement:导入了InfrastructureAdvisorAutoProxyCreator
* 它们都是实现了BeanPostProcessor接口执行InstantiationAwareBeanPostProcessor
* 方法进行后置处理解析切面
*/
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
然后走到AbstractAutoProxyCreator
的postProcessBeforeInstantiation()
方法
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 构建我们的缓存key
Object cacheKey = getCacheKey(beanClass, beanName);
// 以及被解析过 直接返回
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/**
* 判断是不是基础的bean
* 判断是不是应该跳过 (aop解析直接解析出我们的切面信息(并且把切面信息进行保存),
* 而事务在这里是不会解析的)
* 跳过 Advice Pointcut Advisor AopInfrastructureBean 及原始Bean
*/
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
// 进行标记,以后也可以直接进行忽略
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 生成代理对象
// 这个地方一般是不会生成代理对象的(targetSource = null),除非我们的容器中有TargetSourceCreator
// 并且我们的bean需要实现TargetSource接口
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
有两种类型表示该bean不能被增强:1.是切面类型的;2.是原始类型的,原始bean 的后缀是有.ORIGINAL
标志的。下面进入 AspectJAwareAdvisorAutoProxyCreator.java 的shouldSkip
方法,注意千万不要找错了。
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 获得所有的通知者
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
// 如果不是切面类,进入父类方法。如果是原始实例,如果是就返回true,表示其也不能被增强
// 这个方法才是AbstractAutoProxyCreator.java的shouldSkip
return super.shouldSkip(beanClass, beanName);
}
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
然后进入 AnnotationAwareAspectJAutoProxyCreator.java 的findCandidateAdvisors()
方法,它找到接口,注解相关的 Advisor。
@Override
protected List<Advisor> findCandidateAdvisors() {
// 找出事务相关的advisor
List<Advisor> advisors = super.findCandidateAdvisors();
// 找出Aspect相关的信息之后封装为一个advisor
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
// 返回我们所有的通知
return advisors;
}
protected List<Advisor> findCandidateAdvisors() {
// 通过通知者探测器来帮助找到通知(事务相关,这里事务源码中研究)
return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
* 首先尝试从拿到缓存的advisors,如果没有缓存,那么就从bean工厂中尝试找出从bean工厂中寻找继承了
* Advisor.class接口的类,并过滤出单例类型的beanName返回。·如果项目中没有继承接口Advisor的bean,
* 那么直接返回new一个了ArrayList返回。如果有继承Advisor接口的bean,那么就从bean工厂中实例化出来添
* 加到advisors list中返回上层执行后续的代码
*/
public List<Advisor> findAdvisorBeans() {
// 尝试从缓存中拿切面的beanName
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 找到Advisor类型的beanName,如果没有返回的是{}
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
// 若在容器中没有找到,直接返回一个空的集合
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
// ioc容器中找到了我们配置的 BeanFactoryTransactionAttributeSourceAdvisor
for (String name : advisorNames) {
// 判断他是不是一个合适的
if (isEligibleBean(name)) {
// BeanFactoryTransactionAttributeSourceAdvisor是不是正在创建的bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
} else {
try {
// 显示的调用getBean方法创建BeanFactoryTransactionAttributeSourceAdvisor返回
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
// 此处代码省略
}
}
}
}
return advisors;
}
然后进入buildAspectJAdvisors()
方法
public List<Advisor> buildAspectJAdvisors() {
// 用于保存切面的名称,aspectNames 是类级别的缓存,用户缓存已经解析出来的切面信息
List<String> aspectNames = this.aspectBeanNames;
// 缓存字段aspectNames没有值 表示实例化第一个单实例bean的时候就会触发解析切面的操作
if (aspectNames == null) {
// 做了dcl检查
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// 用于保存所有解析出来的Advisors集合对象
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
/**
* aop功能中在这里传入的是Object对象,代表去容器中获取到所有的组件的名
* 称,然后再进行遍历,这个过程是十分的消耗性能的,所以spring会再这里加
* 入了保存切面信息的缓存。但是事务功能不一样,事务模块的功能是直接去容
* 器中获取Advisor类型的,选择范围小,切不消耗性能。所以spring在事务模
* 块中没有加入缓存来保存我们的事务相关的advisor
*/
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历IOC容器中获取处的所有bean的名称
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 通过beanName去容器中获取到对应class对象
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 根据class对象判断是不是切面
if (this.advisorFactory.isAspect(beanType)) {
// 是切面类加入到缓存中
aspectNames.add(beanName);
// 把beanName和class对象构建成为一个AspectMetadata
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 构建切面注解的实例工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 真正的去获取的实例工厂
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 加入到缓存中
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// 此处省略部分代码
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 不是第一次进入,直接区缓存中取
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
// 从缓存取
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
然后就进入到了getAdvisors()
方法,执行解析切面类的详细逻辑
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取标记为Aspect的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取切面类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 校验切面类
validate(aspectClass);
// 使用的是包装模式来包装我们的MetadataAwareAspectInstanceFactory
// 构建为 MetadataAwareAspectInstanceFactory
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取到切面类中的所有方法,但是该方法不会解析标注了@PointCut注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 逐个解析切面中的方法
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
然后看一下getAdvisor()
方法
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 切面的方法上构建 切点表达式(解析切点)
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 实例化我们的切面通知对象 (创建切面)
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
最后解析构建的通知对象ReflectiveAspectJAdvisorFactory
的getAdvice()
方法
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
//获取切面类的class对象
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取切面方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 解析出来的注解信息是否为null
if (aspectJAnnotation == null) {
return null;
}
// 判断class对象是不是切面信息对象
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 判断标注在方法上的注解类型
switch (aspectJAnnotation.getAnnotationType()) {
// 是PointCut注解 那么就抛出异常
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
// 环绕通知 构建AspectJAroundAdvice
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// 前置通知 构建AspectJMethodBeforeAdvice
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// 后置通知 AspectJAfterAdvice
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// 返回通知 AspectJAfterReturningAdvice
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
// 异常通知 AspectJAfterThrowingAdvice
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// 配置构建出来的通知对象
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
至此我们解析切面就结束了,此时我们的注解、接口、xml标注的切面、切点等都会被解析。
三、创建代理
创建代理又可以分为三个步骤
- 获取 Advisors
- Advisors 匹配切点
- 创建代理
① 获取 Advisors
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 获取我们容器中的所有的bean的后置处理器
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 在这里是后置处理器的【第九次调用】 aop和事务都会在这里生存代理对象
Object current = processor.postProcessAfterInitialization(result, beanName);
//若只有有一个返回null 那么直接返回原始的
if (current == null) {
return result;
}
result = current;
}
return result;
}
// 在该后置方法中 事务和aop的代理对象都是在这生成的
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 找到合适的就会被代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
然后进入wrapIfNecessary()
方法,该方法会去寻找方法,判断是否能且需要被代理,并代理它
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 已经被处理过
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 不需要增强的
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 是不是基础的bean 是不是需要跳过的
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果有通知,就创建代理对象
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 合适的通知器不为空
if (specificInterceptors != DO_NOT_PROXY) {
// 打上标记,代表当前的对象已经代理模式处理过了
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 加入到缓存
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
再进入到 getAdvicesAndAdvisorsForBean()
方法,找到合适的通知,在这里我们会发现又链到了上面我吗解析切面类中的的findCandidateAdvisors()
方法,由于我们 之前已经解析了切面、切点并进行了缓存 (切面类的BeanName) 所以只需要到缓存中去取就行了。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到ioc容器中候选的通知(拿到了接口方式的AOP,事务AOP就是从这里拿到的)
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 判断我们的通知能不能作用到当前的类上
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
// 对我们的advisor进行排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
② Advisors 匹配切点
从上一步的代码中进入到findAdvisorsThatCanApply()
方法,匹配切点
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 用来记录当前正在创建的被代理对象的名称
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 从候选的通知器中找到合适正在创建的实例对象
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
// 进入到AOPUtil的findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
然后再进入canApply()
会对筛选出来的Advisor 拿到切点后进行初筛和精筛,获取到合适的增强。关于初筛和精筛就不过多的叙述了,主要功能如下:
- 初筛: 类级别的过来,通过 AspectJ
- 精筛: 匹配所有方法,按切点表达式和方法匹配器匹配,只要有一个匹配上就创建代理
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 初筛
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// .... 省略代码 ....
// // 精筛 循环所有class对象
for (Class<?> clazz : classes) {
// 找到class对象所有的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
// 通过切点表达式来匹配 AspectJ
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
// 通过方法匹配器匹配,内置AOP接口方式
methodMatcher.matches(method, targetClass)) {
// 只有有一个方法匹配上就创建代理
return true;
}
}
}
return false;
}
③ 创建代理
再次回到wrapIfNecessary()
方法,调用createProxy()
方法,原理就是:先判断是否设置了 proxyTargetClass=true 如果是创建 CGLIB 代理,在判断是否有接口,有接口创建 JDK 代理,无接口创建 CGLIB 代理。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建一个代理对象工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 为proxyFactory设置创建jdk代理还是cglib代理
// 是否设置了 proxyTargetClass = true => cglib代理
// 有接口 => jdk 代理 无接口 => cglib 代理
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 把我们的specificInterceptors数组中的Advisor转化为数组形式的
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 为我们的代理工加入通知器,
proxyFactory.addAdvisors(advisors);
// 设置targetSource对象
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 真正的创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
四、代理类的调用
前面已经自己做了基于 Advisor 的 AOP,那么 Spring 也是这样,在执行时,只需要将这些增强添加到被代理的类上即可。
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 获取当前被代理类
TargetSource targetSource = this.advised.targetSource;
Object target = null;
// equals,hashcode等方法不做代理,直接调用
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
// 若执行的class对象是DecoratingProxy 也不要拦截器执行
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 将代理对象放到线程本地变量中
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 将增加器装换为方法执行拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 将拦截器链包装为ReflectiveMethodInvocation并执行
// 责任链统一抽象
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行此方法
retVal = invocation.proceed();
}
//.... 省略代码 ....
}
}
然后将增强器装换为方法拦截器链,最终包装为ReflectiveMethodInvocation执行它的proceed
方法,以 JDK 代理为例
@Override
@Nullable
public Object proceed() throws Throwable {
// 当执行到最后一个拦截器的时候才会进入
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取集合当前需要运行的拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 执行拦截器方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
然后进入到ExposeInvocationInterceptor.java
的invoke()
方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
AspectJAfterAdvice
的invoke()
方法,返回拦截器,方法执行失败,不会调用
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
AspectJAfterAdvice
的invoke()
方法,后置拦截器,总是执行
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
MethodBeforeAdviceInterceptor
的invoke()
方法,后置拦截器,总是执行
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
ThrowsAdviceInterceptor
的invoke()
方法,异常拦截器,异常时执行
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
看到上面的几个通知执行方法没有?都在调用mi.proceed()
就是责任链的递归调用,将所有的通知切入我们的增强类中,SpringAOP就实现了。