2.1 Spring AOP
2.1.1 他是基于动态代理实现的
Spring 提供了很多的实现AOP的方式:Spring 接口方式,schema配置方式和注解的方式.
如果使用接口方式引入AOP, 就是用JDK提供的动态代理来实现.
如果没有使用接口的方式引入. 那么就是使用CGLIB来实现的
研究使用接口方式实现AOP, 目的是为了更好地理解spring使用动态代理实现AOP的两种方
2.1.2 Spring提供了对AspectJ的支持, 但只提供了部分功能的支持: 即AspectJ的切点解析(表达式)和匹配
我们在写切面的时候,经常使用到的@Aspect, @Before, @Pointcut, @After, @AfterReturning, @AfterThrowing等就是AspectJ提供的.
我们知道AspectJ很好用, 效率也很高. 那么为什么Spring不使用AspectJ全套的东西呢? 尤其是AspectJ的静态织入.
先来看看AspectJ有哪些特点
AspectJ的特点
1. AspectJ属于静态织入. 他是通过修改代码实现的. 它的织入时机有三种
1) Compile-time weaving: 编译期织入. 例如: 类A使用AspectJ增加了一个属性. 类B引用了类A, 这个场景就需要在编译期的时候进行织入, 否则类B就没有办法编译, 会报错.
2) Post-compile weaving: 编译后织入.也就是已经生成了.class文件了, 或者是都已经达成jar包了. 这个时候, 如果我们需要增强, 就要使用到编译后织入
3) Loading-time weaving: 指的是在加载类的时候进行织入.
2. AspectJ实现了对AOP变成完全的解决方案. 他提供了很多Spring AOP所不能实现的功能
3. 由于AspectJ是在实际代码运行前就完成了织入, 因此可以认为他生成的类是没有额外运行开销的.
扩展: 这里为什么没有使用到AspectJ的静态织入呢? 因为如果引入静态织入, 需要使用AspectJ自己的解析器. AspectJ文件是以aj后缀结尾的文件, 这个文件Spring是没有办法, 因此要使用AspectJ自己的解析器进行解析. 这样就增加了Spring的成本.
上面说了Spring AOP和AspectJ. 也说道了AspectJ定义了很多注解, 比如: @Aspect, @Pointcut, @Before, @After等等. 但是, 我们使用Spring AOP是使用纯java代码写的. 也就是说他完全属于Spring, 和AspectJ没有什么关系. Spring只是沿用了AspectJ中的概念. 包括AspectJ提供的jar包的注解. 但是, 并不依赖于AspectJ的功能.
Spring AOP有三种配置方式.
因为我们在平时工作中主要使用的是注解的方式配置AOP, 而注解的方式主要是基于第一种接口的方式实现的. 所以, 我们会重点研究第一种和第三种配置方式.
3.1 基于接口方式的配置. 在Spring1.2版本, 提供的是完全基于接口方式实现的
这种方式是最古老的方式, 但由于spring做了很好的向后兼容, 所以, 现在还是会有很多代码使用这种方式, 比如:声明式事务.
那么, 在没有引入AspectJ的时候, Spring是如何实现AOP的呢? 我们来看一个例子:
1.定义一个业务逻辑接口类
/**
* 使用接口方式实现AOP, 默认通过JDK的动态代理来实现. 非接口方式, 使用的是cglib实现动态代理
*
* 业务接口类-- 计算器接口类
*
* 定义三个业务逻辑方法
*/
public interface IBaseCalculate {
int add(int numA, int numB);
int sub(int numA, int numB);
int div(int numA, int numB);
int multi(int numA, int numB);
int mod(int numA, int numB);
}
2.定义业务逻辑类
/**
* 业务实现类 -- 基础计算器
*/
public class BaseCalculate implements IBaseCalculate {
@Override
public int add(int numA, int numB) {
System.out.println("执行目标方法: add");
return numA + numB;
}
@Override
public int sub(int numA, int numB) {
System.out.println("执行目标方法: sub");
return numA - numB;
}
@Override
public int multi(int numA, int numB) {
System.out.println("执行目标方法: multi");
return numA * numB;
}
@Override
public int div(int numA, int numB) {
System.out.println("执行目标方法: div");
return numA / numB;
}
@Override
public int mod(int numA, int numB) {
System.out.println("执行目标方法: mod");
int retVal = ((Calculate) AopContext.currentProxy()).add(numA, numB);
return retVal % numA;
}
}
3. 定义通知类
前置通知
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 定义前置通知
* 实现MethodBeforeAdvice接口
*/
public class BaseBeforeAdvice implements MethodBeforeAdvice {
/**
*
* @param method 切入的方法
* @param args 切入方法的参数
* @param target 目标对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("===========进入beforeAdvice()============");
System.out.println("前置通知--即将进入切入点方法");
System.out.println("===========进入beforeAdvice() 结束============\n");
}
}
后置通知
/**
* 后置通知
* 实现AfterReturningAdvice接口
*/
public class BaseAfterReturnAdvice implements AfterReturningAdvice {
/**
*
* @param returnValue 切入点执行完方法的返回值,但不能修改
* @param method 切入点方法
* @param args 切入点方法的参数数组
* @param target 目标对象
* @throws Throwable
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("\n==========进入afterReturning()===========");
System.out.println("后置通知--切入点方法执行完成");
System.out.println("==========进入afterReturning() 结束=========== ");
}
}
环绕通知
/**
* 环绕通知
* 实现MethodInterceptor接口
*/
public class BaseAroundAdvice implements MethodInterceptor {
/**
* invocation :连接点
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("===========around环绕通知方法 开始===========");
// 调用目标方法之前执行的动作
System.out.println("环绕通知--调用方法之前: 执行");
// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
Object returnValue = invocation.proceed();
System.out.println("环绕通知--调用方法之后: 执行");
System.out.println("===========around环绕通知方法 结束===========");
return returnValue;
}
}
配置类
/**
* 配置类
*/
public class MainConfig {
/**
* 被代理的对象
* @return
*/
@Bean
public IBaseCalculate baseCalculate() {
return new BaseCalculate();
}
/**
* 前置通知
* @return
*/
@Bean
public BaseBeforeAdvice baseBeforeAdvice() {
return new BaseBeforeAdvice();
}
/**
* 后置通知
* @return
*/
@Bean
public BaseAfterReturnAdvice baseAfterReturnAdvice() {
return new BaseAfterReturnAdvice();
}
/**
* 环绕通知
* @return
*/
@Bean
public BaseAroundAdvice baseAroundAdvice() {
return new BaseAroundAdvice();
}
/**
* 使用接口方式, 一次只能给一个类增强, 如果想给多个类增强, 需要定义多个ProxyFactoryBean
* 而且, 曾增强类的粒度是到类级别的. 不能指定对某一个方法增强
* @return
*/
@Bean
public ProxyFactoryBean calculateProxy() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames("baseAfterReturnAdvice", "baseBeforeAdvice", "baseAroundAdvice");
proxyFactoryBean.setTarget(baseCalculate());
return proxyFactoryBean;
}
}
之前说过, AOP是依赖ioc的, 必须将其注册为bean才能实现AOP功能
方法入口
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class InterfaceMainClass{
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
IBaseCalculate calculate = context.getBean("calculateProxy", IBaseCalculate.class);
System.out.println(calculate.getClass());
calculate.add(1, 3);
}
}
执行结果:
===========进入beforeAdvice()============
前置通知--即将进入切入点方法
===========进入beforeAdvice() 结束============
===========around环绕通知方法 开始===========
环绕通知--调用方法之前: 执行
执行目标方法: add
环绕通知--调用方法之后: 执行
===========around环绕通知方法 结束===========
==========进入afterReturning()===========
后置通知--切入点方法执行完成
==========进入afterReturning() 结束===========
通过观察, 我们发现, 执行的顺序是: 前置通知-->环绕通知的前置方法 --> 目标逻辑 --> 环绕通知的后置方法 --> 后置通知.
那么到底是先执行前置通知, 还是先执行环绕通知的前置方法呢? 这取决于配置文件的配置顺序
这里,我们将环绕通知放在最后面, 所以, 环绕通知在前置通知之后执行.
@Bean
public ProxyFactoryBean calculateProxy() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames( "baseAfterReturnAdvice", "baseBeforeAdvice", "baseAroundAdvice");
proxyFactoryBean.setTarget(baseCalculate());
return proxyFactoryBean;
}
那么, 如果我们将环绕通知放在前置通知之前. 就会先执行环绕通知
@Bean
public ProxyFactoryBean calculateProxy() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames("baseAroundAdvice", "baseAfterReturnAdvice", "baseBeforeAdvice");
proxyFactoryBean.setTarget(baseCalculate());
return proxyFactoryBean;
}
运行结果
===========around环绕通知方法 开始===========
环绕通知--调用方法之前: 执行
===========进入beforeAdvice()============
前置通知--即将进入切入点方法
===========进入beforeAdvice() 结束============
执行目标方法: add
==========进入afterReturning()===========
后置通知--切入点方法执行完成
==========进入afterReturning() 结束===========
环绕通知--调用方法之后: 执行
===========around环绕通知方法 结束===========
有一条流水线. 比如生产流水线. 里面有许多道工序. 完成工序1 ,才能进行工序2, 依此类推.
结合上面的demo, 来看一个责任链调用的demo.
上面我们定义了两个方法. 一个是前置通知BaseBeforeAdvice 实现了MethodBeforeAdvice, 另一个是环绕通知BaseAroundAdvice 实现了MethodInterceptor. 如果想把这两个通知放在一个链上. 那么他们必须实现相同的接口. 但是, 现在不同.
我们知道环绕通知, 有两部分, 一部分是环绕通知的前置通知, 一部分是环绕通知的后置通知. 所以, 我们可以将前置通知看作是环绕通知的前置通知部分.
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 为什么 我们可以让MethodBeforeAdvice 前置通知继承自环绕通知的接口呢?
* 主要原因是, 环绕通知的前半部分, 就是前置通知
*/
public class BeforeAdviceInterceptor implements MethodInterceptor {
// 前置通知
MethodBeforeAdvice methodBeforeAdvice;
public BeforeAdviceInterceptor(MethodBeforeAdvice methodBeforeAdvice) {
this.methodBeforeAdvice = methodBeforeAdvice;
}
/**
* 使用了环绕通知的前半部分. 就是一个前置通知
* @param invocation the method invocation joinpoint
* @return
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
methodBeforeAdvice.before(invocation.getMethod(), invocation.getArguments(), invocation.getClass());
return invocation.proceed();
}
}
这段代码包装了前置通知, 让其扩展为实现MethodInterceptor接口. 这是一个扩展接口的方法.
接下来我们要创建一条链. 这条链就可以理解为流水线上各个工人. 每个工人处理一个工序. 为了能够统一调用. 所有的工人都要实现同一个接口. 责任链的定义如下:
/**
* 把一条链上的都初始化
*
* 有一条链, 这条链上都有一个父类接口 MethodInterceptor.
* 也就是说, 链上都已一种类型的工人. 但每种工人的具体实现是不同的. 不同的工人做不同的工作
*
* 这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知.
* 前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor
* 相当于为BaseBeforeAdvice()包装了一层MethodInterceptor
*/
List list = new ArrayList<>();
list.add(new BeforeAdviceInterceptor(new BaseBeforeAdvice()));
list.add(new BaseAroundAdvice());
这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知.
前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor相当于为BaseBeforAdvice()包装了一层MethodInterceptor接下来是责任链的调用.
/**
* 责任链调用
*/
public static class MyMethodInvocation implements MethodInvocation {
// 这是责任链
protected List list;
// 目标类
protected final BaseCalculate target;
public MyMethodInvocation(List list) {
this.list = list;
this.target = new BaseCalculate();
}
int i = 0;
public Object proceed() throws Throwable {
if (i == list.size()) {
/**
* 执行到责任链的最后一环, 执行目标方法
*/
return target.add(2, 2);
}
MethodInterceptor interceptor = list.get(i);
i++;
/**
* 执行责任链调用
* 这个调用链第一环是: 包装后的前置通知
* 调用链的第二环是: 环绕通知.
* 都执行完以后, 执行目标方法.
*/
return interceptor.invoke(this);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return null;
}
@Override
public Method getMethod() {
try {
return target.getClass().getMethod("add", int.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@Override
public Object[] getArguments() {
return new Object[0];
}
}
}
这里重点看 proceed () 方法. 我们循环获取了list责任链的通知, 然后执行invoke()方法
proceed() 方法是一个链式循环. 刚开始i=0, list(0)是前置通知, 当调用到前置通知的时候, BeforeAdviceInterceptor.invoke()方法, 又调用了invocation.proceed()方法, 回到了MyMethodInvocation.proceed()方法.
然后i=1, list(1)是环绕通知, 当调用环绕通知的时候, 又调用了invocation.proceed(); 有回到了MyMethodInvocation.proceed()方法.
这是已经是list的最后一环了, 后面不会在调用invoke()方法了. 二是执行目标方法. 执行结束以后, 整个调用结束.
这就是一个调用链.
1. 要有一个统一的调用, 也就是一个共同的抽象类.
2. 使用循环或者递归, 完成责任链的调用
总结:
上面这种方式, 使用的是ProxyFactoryBean 代理bean工厂的方式. 他有两个限制:
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean
1. 一次只能给1个类增强, 如果给多个类增强就需要定义多个ProxyFactoryBean
2. 增强的粒度只能到类级别上, 不能指定给某个方法增强.这样还是有一定的限制
3.2 基于注解@Aspect的方式. 这种方式是最简单, 方便的. 这里虽然叫做AspectJ, 但实际上和AspectJ一点关系也没有.
3.2.1 @Aspect切面的解析原理
上面第一种方式详细研究了接口方式AOP的实现原理. 注解方式的AOP, 最后就是将@Aspect 切面类中的@Befor, @After等注解解析成Advisor. 带有@Before类会被解析成一个Advisor, 带有@After方法的类也会被解析成一个Advisor.....其他通知的方法也会被解析成Advisor 在Advisor中定义了增强的逻辑, 也就是@Befor和@After等的逻辑, 以及需要增强的方法, 比如div方法.
下面来分析一下使用注解@Aspect , @Before, @After的实现原理. 上面已经说了, 就是将@Before, @After生成Advisor
这里一共有三个部分.
下面我们按照这三个部分来分析.
第一步: 解析@Aspect下带有@Before等的通知方法, 将其解析为Advisor. 如下图:
第一步是在什么时候执行的呢?
在createBean的时候, 会调用很多PostProcessor后置处理器, 在调用第一个后置处理器的时候执行.执行的流程大致是: 拿到所有的BeanDefinition,判断类上是不是带有@Aspect注解. 然后去带有@Aspect注解的方法中找@Before, @After, @AfterReturning, @AfterThrowing, 每一个通知都会生成一个Advisor
第二步: 在createBean的时候, 创建动态代理
createBean一共有三个阶段, 具体在哪一个阶段创建的动态代理呢?
整体流程是:
在createBean的时候, 在初始化完成以后调用bean的后置处理器. 拿到所有的Advisor, 循环遍历Advisor, 然后根据execution中的表达式进行matchs匹配. 和当前创建的这个bean进行匹配, 匹配上了, 就创建动态代理.
pointcut的种类有很多. 上面代码提到过的有:
package com.lxl.www.aop.interfaceAop.chainDemo;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 为什么 我们可以让MethodBeforeAdvice 前置通知继承自环绕通知的接口呢?
* 主要原因是, 环绕通知的前半部分, 就是前置通知
*/
public class BeforeAdviceInterceptor implements MethodInterceptor {
// 前置通知
MethodBeforeAdvice methodBeforeAdvice;
public BeforeAdviceInterceptor(MethodBeforeAdvice methodBeforeAdvice) {
this.methodBeforeAdvice = methodBeforeAdvice;
}
/**
* 使用了环绕通知的前半部分. 就是一个前置通知
* @param invocation the method invocation joinpoint
* @return
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
methodBeforeAdvice.before(invocation.getMethod(), invocation.getArguments(), invocation.getClass());
return invocation.proceed();
}
}
而我们注解里面是按照execution表达式的方式进行匹配的
第三步: 调用. 调用的时候, 执行责任链, 循环里面所有的通知. 最后输出结果.
3.2.2 AOP切面源码分析
源码分析也分为三部分
/**
* 把一条链上的都初始化
*
* 有一条链, 这条链上都有一个父类接口 MethodInterceptor.
* 也就是说, 链上都已一种类型的工人. 但每种工人的具体实现是不同的. 不同的工人做不同的工作
*
* 这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知.
* 前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor
* 相当于为BaseBeforeAdvice()包装了一层MethodInterceptor
*/
List list = new ArrayList<>();
list.add(new BeforeAdviceInterceptor(new BaseBeforeAdvice()));
list.add(new BaseAroundAdvice());
源码分析的入口, AOP注解:
package com.lxl.www.aop;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configurable
// 使用注解的方式引入AOP
@EnableAspectJAutoProxy
@ComponentScan("com.lxl.www.aop")
public class MainConfig {
}
引入AOP, 我们需要在配置文件中增加@EnableAspectJAutoProxy代理. 那么想要去掉AOP的引入, 只需要将这个注解注释掉就可以了. 这个注解解释整个AOP的入口.
接下来, 进入到注解类
/**
* 责任链调用
*/
public static class MyMethodInvocation implements MethodInvocation {
// 这是责任链
protected List list;
// 目标类
protected final BaseCalculate target;
public MyMethodInvocation(List list) {
this.list = list;
this.target = new BaseCalculate();
}
int i = 0;
public Object proceed() throws Throwable {
if (i == list.size()) {
/**
* 执行到责任链的最后一环, 执行目标方法
*/
return target.add(2, 2);
}
MethodInterceptor interceptor = list.get(i);
i++;
/**
* 执行责任链调用
* 这个调用链第一环是: 包装后的前置通知
* 调用链的第二环是: 环绕通知.
* 都执行完以后, 执行目标方法.
*/
return interceptor.invoke(this);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return null;
}
@Override
public Method getMethod() {
try {
return target.getClass().getMethod("add", int.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@Override
public Object[] getArguments() {
return new Object[0];
}
}
}
这是, 我们看到EnableAspectJAutoProxy类增加了一个@Import注解类, 我们知道Import注解可以向IoC容器中增加一个bean.
下面进入到 AspectJAutoProxyRegistrar类
package org.springframework.context.annotation;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
我们看到, 使用ImportBeanDefinitionRegistrar注册了一个BeanDefinition.
需要记住的是, 通常使用ImportBeanDefinitionRegistrar结合@Import可以向容器中注册一个BeanDefinition.
如何注册的呢? 看具体实现.
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
注册名字是internalAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
/**
* 注册一个AnnotationAwareAspectJAutoProxyCreator类型的bean定义
*/
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
如上结构梳理如下:
我们看到, 注册了类AnnotationAwareAspectJAutoProxyCreator类型的bean. 这是一个什么样的类呢? 我们来看一下类的结构. 这个类的继承结构很庞大, 我们只看和本次内容相关的继承结构
解析切面, 创建动态代理, 都是在bean的后置处理器中进行的, 下面对照着AOP的实现原理以及createBean(创建bean)的过程来看
上图是bean加载过程中调用的9次后置处理器. 在创建bean之前调用了InstantiationAwareBeanPostProcessor后置处理器判断是否需要为这个类创建AOP, 也就是解析切面的过程. 所以在AnnotationAwareAspectJAutoProxyCreator里面实现了InstantiationAwareBeanPostProcessor后置处理器的接口. 重写了postProcessBeforeInstantiation方法.
在createBean的第三阶段初始化之后, 要创建AOP的动态代理, 调用了BeanPostProcess后置处理器, AnnotationAwareAspectJAutoProxyCreator也实现了BeanPostProcess接口. 重写了postProcessAfterInitialization.
同时也需要处理AOP的循环依赖的问题, 处理循环依赖是在属性赋值之前调用SmartInstantiationAwareBeanPostProcessor后置处理器, 然后重写getEarlyBeanReference方法. 我们看到AnnotationAwareAspectJAutoProxyCreator也实现了SmartInstantiationAwareBeanPostProcessor接口. 并重写getEarlyBeanReference方法.
第一种: 基于接口方式的配置. 在Spring1.2版本, 提供的是完全基于接口方式实现的
第二种: 基于schema-based配置. 在spring2.0以后使用了xml的方式来配置.
第三种: 基于注解@Aspect的方式. 这种方式是最简单, 方便的. 这里虽然叫做AspectJ, 但实际上和AspectJ一点关系也没有.
第一部分: 解析@Aspect下带有@Before等的通知方法, 将其解析为Advisor
第二部分: 在createBean的时候, 创建动态代理
第三部分: 调用. 调用的时候, 执行责任链, 循环里面所有的通知. 最后输出结果.
1. 解析切面
2. 创建动态代理
3. 调用