文章目录
- 一、概念
- 1、AOP是什么?
- 2、相关概念
- 1)目标对象Target
- 2)通知Advice
- 3)连接点Joinpoint
- 4)切点Pointcut
- 5)切面Aspect
- 6)织入Weaving
- 二、分析
- 三、实现
- 1、实现Advice
- 1)前置通知
- 2)后置通知
- 3)环绕通知
- 4)异常通知
- 5)最终通知
- 2、实现Pointcut
- 1)分析
- 2)具体代码实现
- 3、实现Aspect
- 1)分析
- 2)具体代码实现
- 4、织入实现
- 1)分析
- 2)具体代码实现
- 四、最终完整版本
- 五、总结
一、概念
1、AOP是什么?
AOP[Aspect Oriented Programming] 面向切面编程:在不改类代码的情况下,对类方法进行增强操作
切面:将那些和业务无关的公共逻辑封装起来,方面使用
横切一刀,剖开对象的封装,将多个类的公共行为封装到一个可重用的模块,组成一个切面
2、相关概念
1)目标对象Target
目标对象是实际执行程序的对象,需要被代理的类,切面通过代理目标对象来添加额外的行为。
2)通知Advice
在什么时候进行增强功能
- 前置
- 后置
- 环绕
- 异常
- 最终
3)连接点Joinpoint
可以被选择来进行增强的点,包含切点
4)切点Pointcut
需要增强的点
5)切面Aspect
Advice和Pointcut组合成了切面,定义了在何时和何地完成增强功能
6)织入Weaving
将切面应用到目标对象的方法上,并创建代理对象的过程,可以在编译时、类加载时或运行时进行。
二、分析
所以,我们通过AOP来实现对类方法功能的增强。在已有类和方法的情况下,我们需要写的就是,在什么时候进行增强,方法前还是方法后…也就是Advice,需要对什么方法进行增强,也就是Pointcut,两种共同组成了切面,确定了时间和地点,从而进行功能增强。
Advice
用户性:用户根据需求编写
可选时机:可在方法前、后、异常时进行功能增强
多重性:一个切入点可以有多个增强,可以在方法前以及方法后同时增强
Pointcut
用户性:用户可灵活指定
多点性:可以选择在多个点上进行增强
Weaving:无入侵性,不修改原类的代码
在Spring中,它已经实现了,但这里需要我们自己去实现,后面再具体分析下
三、实现
1、实现Advice
定义一个空接口,方便后续实现不同的可选时机(前置Before、后置AfterReturn、环绕Around、异常Throwing、最终After)
public interface Advice {
}
分析一波:无论什么通知,都是对方法进行增强,所以基本都需要方法的相关信息,后面来看看具体实现
1)前置通知
作用:在方法执行前进行增强
所需的参数:
- 方法所属对象:Object
- 方法本身:Method
- 方法的参数:Object[]
- 返回值:不需要,方法都没执行,哪来的返回值!
具体实现
public interface MethodBeforeAdvice extends Advice {
/**
* 实现该方法进行前置增强
*
* @param method 被增强的方法
* @param args 方法的参数
* @param target 被增强的目标对象
* @throws Throwable
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
2)后置通知
作用:在方法执行成功返回后进行增强
所需的参数:
- 方法所属对象:Object
- 方法本身:Method
- 方法的参数:Object[]
- 方法的返回值:Object,可能有,也可能没有,得看看是否允许在After中更改返回的结果,如果规定只可用、不可修改返回值就不需要返回值;允许更改才需要返回值
具体实现
public interface AfterReturningAdvice extends Advice {
/**
* 实现该方进行后置增强
*
* @param returnValue 返回值
* @param method 被增强的方法
* @param args 方法的参数
* @param target 方法的所属对象
* @throws Throwable
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
3)环绕通知
作用:包裹方法进行增强
所需的参数:
- 方法所属对象:Object
- 方法本身:Method
- 方法的参数:Object[]
- 方法的返回值:Object,方法将由它来执行,它需要返回方法的返回值
具体实现
public interface MethodInterceptor extends Advice {
/**
* 实现该方法进行环绕(前置、后置)增强、异常处理增强
*
* @param method 被增强的方法
* @param args 方法的参数
* @param target 方法所属对象
* @return Object 返回值
* @throws Throwable
*/
Object invoke(Method method, Object[] args, Object target) throws Throwable;
}
4)异常通知
作用:对方法执行时的异常,进行增强处理
参数说明:
- 必须的参数:Exception
- 可能需要的参数:
- 方法所属对象:Object
- 方法本身:Method
- 方法的参数:Object[]
具体实现
public interface ThrowsAdvice extends Advice {
/**
* 实现该方法进行异常处理增强
*
* @param method 被增强的方法
* @param args 方法的参数
* @param target 方法所属对象
* @param ex 抛出的异常
* @return
*/
void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable;
}
5)最终通知
作用:在方法执行后进行增强
所需的参数:
- 方法所属对象:Object
- 方法本身:Method
- 方法的参数:Object[]
- 方法的返回值:Object,可能有,也可能没有,得看看是否允许在After中更改返回的结果,如果规定只可用、不可修改返回值就不需要返回值;允许更改才需要返回值
具体实现
public interface AfterAdvice extends Advice {
/**
* 实现该方法进行最终增强
*
* @param returnValue 返回值
* @param method 被增强的方法
* @param args 方法的参数
* @param target 方法的所属对象
* @throws Throwable
*/
void after(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
通知类的类图类图如下:
2、实现Pointcut
其实就是指定要增强的方法
1)分析
那么我们应该怎么指定要增强的方法?要求满足用户灵活控制,并且程序也能轻松识别
首先应该怎么描述指定一个方法?方法可能有重载的情况?如下:
com.forlan.test(int,string)
com.forlan.test(int)
还要满足灵活控制,以及支持多个点增强,情况可能有如下很多种:
某包下某个类的某个方法
某包下某个类的所有方法
某包下所有类的所有方法
某包下以Service结尾的类中,以xx开头的方法
…
所以我们需要一个表达式能够灵活地去描述,匹配到目标方法名,类似:包名.类名.方法名(参数类型)
需要满足的要求:
- 包名、类名、方法名:支持模糊匹配
- 参数类型:可能有多个
所以可以使用AspectJ表达式,官网:http://www.eclipse.org/aspectj
语法格式
execution([访问权限类型] 返回值类型 [全限定性类名] 方法名(参数名) [抛出的异常类型])
execution表达式中就是方法的签名
表达式中加[ ]的部分表示可省略
各部分用空格分开
可以使用的符号:
*:0至多个字符
…:用在方法参数中表示任意多个参数,用在包名后表示当前包及其子包路径
+:用在类名后表示当前类及子类,用在接口后表示接口及实现类
例子
- 任意公共方法:execution(public * *(. .))
- 任何一个以“set”开始的方法:execution(* set *(. .))
- 定义在service包里的任意类的任意方法:execution(* com.forlan.service..(. .))
所以,最终就是,用户通过指定AspectJ表达式,程序去解析表达式中需要增强的类中的方法。
2)具体代码实现
定义一个接口,提供需要匹配的类和方法
public interface Pointcut {
boolean matchsClass(Class<?> targetClass);
boolean matchsMethod(Method method, Class<?> targetClass);
}
定义实现类,用aspectj工具包识别表达式,大概思路就是先匹配类,再匹配方法
public class AspectJExpressionPointcut implements Pointcut {
private static PointcutParser pp = PointcutParser
.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
private String expression;
private PointcutExpression pointcutExpression;
public AspectJExpressionPointcut(String expression) {
super();
this.expression = expression;
pointcutExpression = pp.parsePointcutExpression(expression);
}
@Override
public boolean matchsClass(Class<?> targetClass) {
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matchsMethod(Method method, Class<?> targetClass) {
ShadowMatch sm = pointcutExpression.matchesMethodExecution(method);
return sm.alwaysMatches();
}
public String getExpression() {
return expression;
}
}
3、实现Aspect
1)分析
其实就是前面的Advice和Pointcut的组合
- 通过Advice确定何时进行什么增强
- 通过Pointcut确定何地(目标方法)进行增强
我们参考Spring定义Advisor来描述组合Advice和Pointcut
在Spring框架中,Advisor是一个用于提供切面(Aspect)功能的对象。它用于定义切入点(Pointcut)和通知(Advice)之间的关系。通常,Advisor会根据切入点来确定在何时和何地应用通知。通知可以是在方法执行前、执行后或抛出异常时执行的代码。Advisor可以通过配置或编程方式添加到Spring应用程序中,以实现横切关注点的功能,例如日志记录、事务管理等。
2)具体代码实现
定义一个接口
public interface Advisor {
String getAdviceBeanName();
String getExpression();
}
定义基于切点的接口
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
基于AspectJ切点的实现类
public class AspectJPointcutAdvisor implements PointcutAdvisor {
private String adviceBeanName;
private String expression;
private Pointcut pointcut;
public AspectJPointcutAdvisor(String adviceBeanName, String expression) {
super();
this.adviceBeanName = adviceBeanName;
this.expression = expression;
this.pointcut = new AspectJExpressionPointcut(this.expression);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public String getAdviceBeanName() {
return this.adviceBeanName;
}
@Override
public String getExpression() {
return this.expression;
}
}
实现的类图结构如下:
4、织入实现
其实就是把用户提供的增强方法,加到指定的方法上
1)分析
在什么时候织入?
在Bean初始化后,对其进行增强
如何实现织入?
主要讨论的是运行时织入,可以通过使用动态代理或字节码生成技术,在目标对象的方法执行前后插入切面代码。
如何确定Bean需要增强?
Bean类及其方法和与切面进行匹配,匹配到,表示需要增强
如果增强的方法,写在Bean生命周期过程中,也就是在BeanFactory中找到对应的方法,在方法前、后等位置写代码,这样的话,代码会越来越复杂,不好拓展
考虑到拓展性:在不修改BeanFactory中代码的情况下,实现灵活扩展,可以考虑使用观察者模式,在各个节点加入扩展点,增加一个Bean的处理器BeanPostProcessor,先注册到BeanFactory,后面在初始化前后的处理中,再遍历执行BeanPostProcessor增强1
总的来说,BeanFactory实现相关Bean的增强操作,需要做两件事:
- 创建相关的BeanPostProcessor,并注册到BeanFactory中
- BeanFactory在初始化Bean的前后增加判断,判断是否有相关BeanPostProcessor,如果有就进行相关的增强处理
2)具体代码实现
定义BeanPostProcessor接口,定义初始化之前和初始化之后要执行的方法,默认返回原始bean,表示不增强
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws Throwable {
return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName) throws Throwable {
return bean;
}
}
让BeanFactory支持注册BeanPostProcessor
void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor);
DefaultBeanFactory实现支持注册BeanPostProcessor,并且在Bean对象初始化前后,校验是否需要进行增强,主要调整doCreateInstance方法
// Bean增强相关处理类
private List<BeanPostProcessor> beanPostProcessors = Collections.synchronizedList(new ArrayList<>());
@Override
public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.add(beanPostProcessor);
}
private Object doCreateInstance(String beanName, BeanDefinition bd) throws Exception {
Class<?> beanClass = bd.getBeanClass();
Object instance = null;
if (beanClass != null) {
if (StringUtils.isBlank(bd.getFactoryMethodName())) {
// 构造方法来构造对象
instance = this.createInstanceByConstructor(bd);
} else {
// 静态工厂方法
instance = this.createInstanceByStaticFactoryMethod(bd);
}
} else {
// 工厂bean方式来构造对象
instance = this.createInstanceByFactoryBean(bd);
}
// 赋值前暴露半成品对象
this.doEarlyExposeBuildingBeans(beanName, instance);
// 支持属性依赖
this.setPropertyDIValues(bd, instance);
// 赋完值移除
this.removeEarlyExposeBuildingBeans(beanName);
// bean初始化前的处理
instance = this.applyPostProcessBeforeInitialization(instance, beanName);
// 执行初始化方法
this.doInit(bd, instance);
// bean初始化后的处理
instance = this.applyPostProcessAfterInitialization(instance, beanName);
return instance;
}
private Object applyPostProcessBeforeInitialization(Object bean, String beanName) throws Exception {
for (BeanPostProcessor bpp : this.beanPostProcessors) {
bean = bpp.postProcessBeforeInitialization(bean, beanName);
}
return bean;
}
private Object applyPostProcessAfterInitialization(Object bean, String beanName) throws Exception {
for (BeanPostProcessor bpp : this.beanPostProcessors) {
bean = bpp.postProcessAfterInitialization(bean, beanName);
}
return bean;
}
实现织入,通过创建Bean对应的代理对象来处理
代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在调用者和目标对象之间起到中介的作用。
方式有:JDK动态代理,Cglib动态代理,Javassist、ASM
通过 抽象
和 面向接口编程
来设计一套支持不同代理实现的代码,类图结构如下:
定义上层接口
public interface AopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader);
}
JDK动态代理,实现AopProxy,同时实现InvocationHandler,创建动态代理对象,重写invoke方法来处理代理对象的方法调用
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private String beanName;
private Object target;
private List<Advisor> matchAdvisors;
private BeanFactory beanFactory;
public JdkDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
this.beanName = beanName;
this.target = target;
this.matchAdvisors = matchAdvisors;
this.beanFactory = beanFactory;
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
}
}
Cglib动态代理,实现AopProxy,同时实现MethodInterceptor ,创建动态代理对象,重写intercept方法对目标对象的方法进行拦截和增强
public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {
private static Enhancer enhancer = new Enhancer();
private String beanName;
private Object target;
private List<Advisor> matchAdvisors;
private BeanFactory beanFactory;
public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
this.beanName = beanName;
this.target = target;
this.matchAdvisors = matchAdvisors;
this.beanFactory = beanFactory;
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
Class<?> superClass = this.target.getClass();
enhancer.setSuperclass(superClass);
enhancer.setInterfaces(this.getClass().getInterfaces());
enhancer.setCallback(this);
Constructor<?> constructor = null;
try {
constructor = superClass.getConstructor(new Class<?>[] {});
} catch (NoSuchMethodException | SecurityException e) {
}
if (constructor != null) {
return enhancer.create();
} else {
BeanDefinition bd = ((DefaultBeanFactory) beanFactory).getBeanDefinition(beanName);
// 利用BeanDefinition的缓存,直接拿到真正的参数
return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
}
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
}
}
创建代理对象的过程中,可能需要有参构造参数,这个在前面创建原Bean的时候,已经解析过,我们调整下BeanDefinition,增加缓存
/**
* 获取真正的入参
*/
Object[] getConstructorArgumentRealValues();
void setConstructorArgumentRealValues(Object[] values);
GenericBeanDefinition
private ThreadLocal<Object[]> realConstructorArgumentValues = new ThreadLocal<>();
@Override
public Object[] getConstructorArgumentRealValues() {
return realConstructorArgumentValues.get();
}
@Override
public void setConstructorArgumentRealValues(Object[] values) {
realConstructorArgumentValues.set(values);
}
调整DefaultBeanFactory的createInstanceByConstructor方法,在解析完有参构造参数后,缓存一份到BeanDefinition
private Object createInstanceByConstructor(BeanDefinition bd) throws Exception {
// 1、获取参数值
Object[] args = this.getConstructorArgumentValues(bd);
// 缓存构造参数,方便后续创建代理
bd.setConstructorArgumentRealValues(args);
// 2、确定调用什么构造方法来创建实例
Constructor constructor = this.determineConstructor(bd, args);
return constructor.newInstance(args);
}
不管用哪种方式来生成代理对象,最终增强的逻辑代码是一样的,那么就可以提炼抽取为公共代码
public class AopProxyUtils {
/**
* 对方法应用增强
*/
public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> matchAdvisors,
Object proxy, BeanFactory beanFactory) throws Throwable {
// 获取要对当前方法进行增强的advice
List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, matchAdvisors, beanFactory);
if (CollectionUtils.isEmpty(advices)) {
return method.invoke(target, args);
} else {
// 存在增强的advice,进行增强
AopAdviceChainInvocation chain = new AopAdviceChainInvocation(proxy, target, method, args, advices);
return chain.invoke();
}
}
private static List<Object> getShouldApplyAdvices(Class<?> beanClass, Method method, List<Advisor> matchAdvisors, BeanFactory beanFactory) throws Exception {
if (CollectionUtils.isEmpty(matchAdvisors)) {
return null;
}
List<Object> advices = new ArrayList<>();
for (Advisor ad : matchAdvisors) {
if (ad instanceof PointcutAdvisor) {
if (((PointcutAdvisor) ad).getPointcut().matchsMethod(method, beanClass)) {
advices.add(beanFactory.getBean(ad.getAdviceBeanName()));
}
}
}
return advices;
}
}
对于多种通知类型,有执行顺序,我们通过责任链模式来实现
public class AopAdviceChainInvocation {
private static Method invokeMethod;
static {
try {
invokeMethod = AopAdviceChainInvocation.class.getMethod("invoke", null);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
private Object proxy;
private Object target;
private Method method;
private Object[] args;
private List<Object> advices;
public AopAdviceChainInvocation(Object proxy, Object target, Method method, Object[] args, List<Object> advices) {
super();
this.proxy = proxy;
this.target = target;
this.method = method;
this.args = args;
this.advices = advices;
}
// 责任链执行记录索引号
private int index = 0;
public Object invoke() throws Throwable {
if (index < this.advices.size()) {
Object advice = this.advices.get(index++);
if (advice instanceof MethodBeforeAdvice) {
// 执行前置增强
((MethodBeforeAdvice) advice).before(method, args, target);
} else if (advice instanceof MethodInterceptor) {
// 执行环绕增强,这里的method和对象是invoke方法和链对象
return ((MethodInterceptor) advice).invoke(invokeMethod, null, this);
} else if (advice instanceof AfterReturningAdvice) {
// 执行后置增强,返回成功才触发
Object returnValue = this.invoke();
((AfterReturningAdvice) advice).afterReturning(returnValue, method, args, target);
return returnValue;
} else if (advice instanceof AfterAdvice) {
// 执行最终增强
Object returnValue = null;
try {
returnValue = this.invoke();
} finally {
((AfterAdvice) advice).after(returnValue, method, args, target);
}
return returnValue;
} else if (advice instanceof ThrowsAdvice) {
try {
return this.invoke();
} catch (Exception e) {
// 执行异常增强,发生异常才触发
((ThrowsAdvice) advice).afterThrowing(method, args, target, e);
}
}
return this.invoke();
} else {
return method.invoke(target, args);
}
}
}
定义AOP代理工厂,方便我们获取不同的代理
public interface AopProxyFactory {
AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory);
static AopProxyFactory getDefaultAopProxyFactory() {
return new DefaultAopProxyFactory();
}
}
具体AOP代理工厂实现
public class DefaultAopProxyFactory implements AopProxyFactory {
@Override
public AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
// 是该用jdk动态代理还是cglib?
if (shouldUseJDKDynamicProxy(bean, beanName)) {
return new JdkDynamicAopProxy(beanName, bean, matchAdvisors, beanFactory);
} else {
return new CglibDynamicAopProxy(beanName, bean, matchAdvisors, beanFactory);
}
}
private boolean shouldUseJDKDynamicProxy(Object bean, String beanName) {
// 有实现接口就用JDK,没有就用Cglib
return bean.getClass().isInterface();
}
}
前面我们的增强通过代理来实现,那什么时候需要进行增强,在什么地方增强,就需要获取我们定义的切面、切点、通知类,这些都在Spring容器中了,我们只需要获取到BeanFactory对象,就能拿到它们,那么,怎么在BeanPostProcessor中获取到这个对象?我们可以参考Spring的做法
在Springboot中,通过实现这些"Aware"接口,Spring容器会在适当的时候将相应的资源或环境注入到实现类中,使其能够访问和利用这些资源或环境。例如,实现BeanFactoryAware接口的类可以获取对BeanFactory的引用。
定义Aware接口,Aware的意思就是意识,xxxAware可以理解为具备xxx意识
public interface Aware {
}
定义BeanFactoryAware继承Aware接口
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory bf);
}
调整DefaultBeanFactory的registerBeanPostProcessor,在注册BeanPostProcessor的同时,判断实现了BeanFactoryAware接口的话,就把当前BeanFactory设置给BeanPostProcessor,方便BeanPostProcessor去使用
@Override
public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof BeanFactoryAware) {
((BeanFactoryAware) beanPostProcessor).setBeanFactory(this);
}
}
新增AdvisorAutoProxyCreator类,实现BeanPostProcessor和BeanFactoryAware,重写postProcessAfterInitialization进行Bean初始化后的增强,重写setBeanFactory,在注册的时候,自动设置BeanFactory,方便后续使用
public class AdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {
private BeanFactory beanFactory;
private List<Advisor> advisors;
// 标识是否获取过了所有的Advisors
private volatile boolean gettedAllAdvisors = false;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
// 跳过指定类型的增强
if (bean instanceof Advisor || bean instanceof Advice) {
return bean;
}
// 判断Bean是否需要增强,根据配置的切面,找出匹配的切面
List<Advisor> matchAdvisors = getMatchedAdvisors(bean, beanName);
// 如有匹配的切面,创建代理来实现增强
if (CollectionUtils.isNotEmpty(matchAdvisors)) {
bean = this.createProxy(bean, beanName, matchAdvisors);
}
return bean;
}
private List<Advisor> getMatchedAdvisors(Object bean, String beanName) throws Exception {
// 第一次执行该方法,先从BeanFactory中得到用户配置的所有切面Advisor
if (!gettedAllAdvisors) {
synchronized (this) {
if (!gettedAllAdvisors) {
advisors = this.beanFactory.getBeansOfTypeList(Advisor.class);
gettedAllAdvisors = true;
}
}
}
// 如果没有配置切面,直接返回
if (CollectionUtils.isEmpty(this.advisors)) {
return null;
}
// 有配置切面,获取Bean的类以及所有的方法
Class<?> beanClass = bean.getClass();
List<Method> allMethods = this.getAllMethodForClass(beanClass);
// 用于存放匹配的Advisor
List<Advisor> matchAdvisors = new ArrayList<>();
// 遍历Advisor来匹配
for (Advisor advisor : this.advisors) {
if (advisor instanceof PointcutAdvisor) {
if (isPointcutMatchBean((PointcutAdvisor) advisor, beanClass, allMethods)) {
matchAdvisors.add(advisor);
}
}
}
return matchAdvisors;
}
// 获得本类以及所实现的接口的方法
private List<Method> getAllMethodForClass(Class<?> beanClass) {
List<Method> allMethods = new LinkedList<>();
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(beanClass));
classes.add(beanClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method m : methods) {
allMethods.add(m);
}
}
return allMethods;
}
private boolean isPointcutMatchBean(PointcutAdvisor pa, Class<?> beanClass, List<Method> methods) {
Pointcut p = pa.getPointcut();
// 首先判断类是否匹配
if (!p.matchsClass(beanClass)) {
return false;
}
// 再判断方法是否匹配
for (Method method : methods) {
if (p.matchsMethod(method, beanClass)) {
return true;
}
}
return false;
}
private Object createProxy(Object bean, String beanName, List<Advisor> matchAdvisors) throws Exception {
// 通过AopProxyFactory工厂去选择、和创建代理对象
return AopProxyFactory.getDefaultAopProxyFactory().createAopProxy(bean, beanName, matchAdvisors, beanFactory)
.getProxy();
}
@Override
public void setBeanFactory(BeanFactory bf) {
this.beanFactory = bf;
}
}
四、最终完整版本
五、总结
总的来说,Advice制定触发时机和增强功能;Pointcut制定触发位置,通过AspectJ表达式匹配到目标类的目标方法;Aspect将Advice和Pointcut组装在一起,方便后续Weaving获取;Weaving通过把BeanPostProcessor注册到BeanFactory中,在Bean初始化前后预留方法处理BeanPostProcessor实现增强,通过Aspect获取Pointcut来判断Bean是否匹配,然后通过动态代理来创建代理对象来增强,通过去Aspect获取Advice去执行相关的增强,使用责任链模式来控制增强多少次。