在这里插入图片描述

上面两篇内容说到了手写IOC和DI,本篇内容就是手写AOP,由于内容中使用到了上面两篇内容写的代码,所以此处贴下链接:

手写Spring IOC容器:点击进入

手写Spring DI依赖注入:点击进入

AOP是什么

Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类的方法进行功能增强

那么如果要实现一个AOP,需要做的事情就是要向使用的用户提供AOP功能,能够通过AOP技术实现对类的方法进行功能增强

AOP中的元素

  • Advice 通知,即增强的功能
  • Join points 连接点,可以选择的方法点,即有哪些可以增强的方法供选择
  • Pointcut 切入点,选择切入的方法点,即对哪些方法进行增强
  • Aspact 切面,选择的多个方法点 + 增强的功能,即Advice和Pointcut的组合
  • Introduction 引入,添加新的方法、属性到已经存在的类中,叫做引入
  • Weaving 织入,即不改变原来的代码,加入增强的功能

手写AOP的话,上面几个元素有的是需要用户提供的:Advice、Pointcut、Aspact,用户需要提供增强的功能和切入点、切面信息;AOP框架需要提供Join points、Weaving

AOP提供的功能

  • 需要功能的增强,即Advice通知
  • 对类的方法进行增强,那需要可以选择的要增强的方法点,即Pointcut切入点
  • 需要在不改变原类代码的情况下,进行功能的增强,即Weaving织入

图解AOP
在这里插入图片描述
假设我们现在玩一局王者荣耀,选择了一个英雄鲁班,这个鲁班需要参与整个游戏直到结束,不管是否挂机;刚刚开始的时候,没有任何装备,假设鲁班身上的各个部位是Join points,即这些部位需要装备去增强它,那每一个装备就是Advice增强的功能,比如增加攻速、生命等,现在买了一个鞋子,那么就是选择在速度上进行增强,即穿在脚上,那么就是Pointcut,那么这个鞋子加上脚就是Aspact切面,上面说的例子可能不够好,见谅啊!

特点分析

  1. Advice

实现一个Advice,就需要知道Advice有哪些特点,从上面可以知道Advice是用户来提供的,所以有很多不可控的因素

  • 用户性:由用户来提供增强的功能,即增强功能的代码是用户来进行编写的
  • 多变性:既然用户来提供,那么对于不同的需求,增强的逻辑都是不一样的
  • 可选时机:用户可以选择在方法的前面、后面、异常时进行功能增强
  • 多重性:同一个切入点,即同一个方法,可以有多重的增强,不止增强一次
  1. Pointcut

切入点,通过上面知道它也是用户提供的,所以它的特点和Advice基本上差不多

  • 用户性:由用户来指定,对哪些方法进行功能增强
  • 多变性:用户可以灵活的来指定
  • 多点性:用户可以选择在多个方法点上进行功能增强
  1. Weaving

织入,这部分代码,是需要框架提供的,即是需要我们自己去实现的逻辑,通过这个可以把增强的功能加入到用户指定的方法上面

  • 无侵入性:不改变原来类的代码,去实现功能的增强
  • 需要我们在AOP框架中自己实现逻辑

通过上面的内容,可以知道,需要做的事情就是Advice、Pointcut、Weaving三个部分,Join points为什么不需要去实现呢,这部分内容在编写代码的过程中就可以知道了

Advice是由用户来实现的,这部分逻辑需要用户写好然后我们实现AOP的时候来进行使用;我们需要认识用户的东西,用户需要使用我们写的框架,而且还需要隔绝用户的多变性

那么需要做的事情是啥呢,可以定义一个标准的接口,用户通过实现接口来提供不同的增强逻辑,这就是应对变化的方式,面向接口编程

定义的Advice是一个顶级接口,不需要写任何的方法,然后根据前置、后置、环绕、异常增强,来去实现Advice接口,那么这些增强需要的参数是一样的吗,请往下看

Advice接口:

  1. /**
  2. * @className: Advice
  3. * @description: 通知的标准接口
  4. * @author TR
  5. */
  6. public interface Advice {
  7. }

首先,我们知道,增强是对方法进行增强,那么使用Advice的时候,需要给的就是方法的一些信息

  1. 前置增强

在方法执行前进行增强,那么可以知道前置增强是不需要返回值的,需要的参数如下:

  • 方法自身 Method
  • 方法的参数 Object[]
  • 方法所在的类(对象) Object
  1. 后置增强

在方法执行后进行增强,那需要的参数是不是需要增加一个啊,即需要方法的返回值,因为我如果需要对返回值做一下处理,就需要用到它,而且后置增强也是不需要返回值的,需要的参数如下:

  • 方法自身 Method
  • 方法的参数 Object[]
  • 方法所在的类(对象) Object
  • 方法的返回值 Object
  1. 环绕增强

包裹方法进行增强,它是需要包裹整个方法,即方法由它来执行,那么环绕增强是需要返回值的,这个返回值是需要增加方法的返回值,需要的参数如下:

  • 方法自身 Method
  • 方法的参数 Object[]
  • 方法所在的类(对象) Object
  1. 异常增强

捕获方法执行时的异常信息,然后进行增强,而且它也是需要包裹方法进行增强的,即它可以在环绕增强中来实现

通过上面知道,需要定义三个方法:前置增强的方法、后置增强的方法、环绕和异常增强的方法,那这三个方法是定义在一个接口里面,还是分三个接口呢,根据单一职责原则,还是分三个接口来实现比较好,而且还可以根据不同的接口类型来区分是哪个Advice

定义前置增强接口MethodBeforeAdvice:

  1. /**
  2. * @className: MethodBeforeAdvice
  3. * @description: 前置增强接口
  4. * @author TR
  5. */
  6. public interface MethodBeforeAdvice extends Advice {
  7. /**
  8. * 前置增强方法
  9. * @param method: 将要被执行的方法
  10. * @param target: 执行方法的目标对象
  11. * @param args: 执行方法的参数
  12. * @return: void
  13. **/
  14. void before(Method method, Object target, Object[] args);
  15. }

定义后置增强接口AfterReturningAdvice:

  1. /**
  2. * @className: AfterReturningAdvice
  3. * @description: 后置增强接口
  4. * @author TR
  5. */
  6. public interface AfterReturningAdvice extends Advice {
  7. /**
  8. * 后置增强方法
  9. * @param method: 将要被执行的方法
  10. * @param target: 执行方法的目标对象
  11. * @param args: 执行方法的参数
  12. * @param returnValue: 执行方法的返回值
  13. * @return: void
  14. **/
  15. void after(Method method, Object target, Object[] args, Object returnValue);
  16. }

定义环绕、异常增强接口MethodInterceptor:

  1. /**
  2. * @className: MethodInterceptor
  3. * @description: 环绕、异常增强接口
  4. * @author TR
  5. */
  6. public interface MethodInterceptor extends Advice {
  7. /**
  8. * 环绕、异常增强方法,在方法实现中需要调用目标方法
  9. * @param method: 将要被执行的方法
  10. * @param target: 执行方法的目标对象
  11. * @param args: 执行方法的参数
  12. * @return: java.lang.Object 执行方法的返回值
  13. * @throws Throwable
  14. **/
  15. Object invoke(Method method, Object target, Object[] args) throws Throwable;
  16. }

类图如下:
在这里插入图片描述

Pointcut的特点:

  • 用户性:由用户来指定,对哪些方法进行功能增强
  • 多变性:用户可以灵活的来指定
  • 多点性:用户可以选择在多个方法点上进行功能增强

我们需要给用户提供一个东西,让用户可以灵活的来指定方法点,而且我们获取到的时候又能够知道,用户对哪些方法点进行了指定

指定对哪些方法进行增强,指定的信息是什么,其实就是一个或者多个方法,而且如果有重载存在呢,所以这个指定的东西,就是一个完整的方法签名

那该怎么做到灵活性、多点性呢,这个指定的信息是可以描述一类方法的,比如:

  • 某个包下某个类的某个方法
  • 某个包下某个类的所有方法
  • 某个包下所有类中以get开头的方法
  • 某个包下所有类中以get开头以sevice结尾的方法
  • 某个包下及其子包下所有类中以get开头以sevice结尾的方法

那么可以定义一个表达式,来去描述上面的信息,这个描述的信息是包名.类名.方法名(参数类型)

每一部分是如何要求的呢?

  • 包名:需要有父子特点,可以模糊匹配
  • 类名:可以模糊匹配
  • 方法名:可以模糊匹配
  • 参数类型:可以有多个

定义的表达式是需要来判断:是否需要对某个类的某个方法进行增强,那么需要去匹配类和匹配方法

匹配的表达式:

  • 正则表达式
  • AspactJ表达式

AspactJ表达式学习

  1. /**
  2. * @className: AspectJTest
  3. * @description: AspectJ测试类
  4. */
  5. public class AspectJTest {
  6. public static void main(String[] args) throws NoSuchMethodException {
  7. //获得切点解析器
  8. PointcutParser pp = PointcutParser
  9. .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
  10. //切点解析器根据规则,解析出一个类型匹配器
  11. TypePatternMatcher tp = pp.parseTypePattern("di.*");
  12. //根据表达式生成一个切点表达式
  13. PointcutExpression pe = pp.parsePointcutExpression("execution(* demo.beans.BeanFactory.get*(..))");
  14. //匹配MagicGril的getName方法
  15. Class<?> cl = MagicGril.class;
  16. Method method = cl.getMethod("getName", null);
  17. //匹配方法执行
  18. ShadowMatch sm = pe.matchesMethodExecution(method);
  19. System.out.println("是否匹配到方法:" + sm.alwaysMatches());
  20. System.out.println(cl.getName() + ",是否匹配表达式:" + pe.couldMatchJoinPointsInType(cl));
  21. System.out.println(DefaultBeanFactory.class + ",是否匹配表达式:" + pe.couldMatchJoinPointsInType(DefaultBeanFactory.class));
  22. System.out.println(cl.getName() +"类下的所有方法:");
  23. for (Method method1 : cl.getMethods()) {
  24. System.out.println(method1.getName());
  25. }
  26. }
  27. }

输出结果:
在这里插入图片描述
通过上面的描述,可以知道,切点该怎么去设计了

切点需要有的属性就是切点表达式,需要提供的功能就是匹配类和匹配方法

而且这里也可以像Advice一样定义一个顶级接口,因为如果以后有其他的表达式更加好用的话,需要扩展,那么只需要继承定义的这个顶级接口就行了,不管它内部如何实现,都要去实现我们定义的匹配类和匹配方法的行为

  1. /**
  2. * @className: PointCut
  3. * @description: 切点匹配接口
  4. * @author: TR
  5. */
  6. public interface PointCut {
  7. /**
  8. * 匹配类
  9. * @author: jinpeng.sun
  10. * @date: 2021/4/19 13:46
  11. * @param targetClass: 匹配的目标类
  12. * @return: boolean
  13. **/
  14. boolean matchClass(Class<?> targetClass);
  15. /**
  16. * 匹配方法
  17. * @author: jinpeng.sun
  18. * @date: 2021/4/19 13:46
  19. * @param method: 匹配的目标方法
  20. * @param targetClass: 匹配的目标类
  21. * @return: boolean
  22. **/
  23. boolean matchMethod(Method method, Class<?> targetClass);
  24. }

此处不实现,主要使用AspactJ的方式

  1. /**
  2. * @className: RegExpressionPointcut
  3. * @description: 正则表达式实现类
  4. * @author: TR
  5. */
  6. public class RegExpressionPointcut implements PointCut {
  7. @Override
  8. public boolean matchClass(Class<?> targetClass) {
  9. return false;
  10. }
  11. @Override
  12. public boolean matchMethod(Method method, Class<?> targetClass) {
  13. return false;
  14. }
  15. }
  1. /**
  2. * @className: AspectJExpressionPointcut
  3. * @description: AspectJ切点表达式实现类
  4. * @author: TR
  5. */
  6. public class AspectJExpressionPointcut implements PointCut {
  7. /** 获得切点解析器 */
  8. PointcutParser pp = PointcutParser
  9. .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
  10. /** 切点表达式的字符串形式 */
  11. private String expression;
  12. /** AspectJ中的切点表达式 */
  13. private PointcutExpression pe;
  14. public AspectJExpressionPointcut(String expression) {
  15. super();
  16. this.expression = expression;
  17. pe = pp.parsePointcutExpression(expression);
  18. }
  19. @Override
  20. public boolean matchClass(Class<?> targetClass) {
  21. return pe.couldMatchJoinPointsInType(targetClass);
  22. }
  23. @Override
  24. public boolean matchMethod(Method method, Class<?> targetClass) {
  25. ShadowMatch sm = pe.matchesMethodExecution(method);
  26. return sm.alwaysMatches();
  27. }
  28. public String getExpression() {
  29. return expression;
  30. }
  31. }

实现步骤:

  1. maven引入Aspectj的jar
  1. <dependency>
  2. <groupId>org.aspectj</groupId>
  3. <artifactId>aspectjweaver</artifactId>
  4. <version>1.9.6</version>
  5. </dependency>
  1. 获得切点解析器
  1. PointcutParser pp = PointcutParser
  2. .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
  1. 解析切点表达式,获得PointcutExpression
  1. PointcutExpression pe = pp.parsePointcutExpression(
  2. "execution(* edu.dongnao.courseware.beans.BeanFactory.get*(..))");
  1. 使用PointcutExpression匹配类,不可靠
  1. pe.couldMatchJoinPointsInType(targetClass)
  1. 使用PointcutExpression匹配方法,可靠
  1. ShadowMatch sm = pe.matchesMethodExecution(method);
  2. return sm.alwaysMatches();

类图如下:
在这里插入图片描述

上面实现了Advice和Pointcut,那么用户该如何使用呢?

Advice是用户提供的功能增强实现,是需要继承接口的,那么可以把Advice配置成一个bean,Pointcut是切点表达式,是用来匹配类和方法的,是不需要配置成bean的,只需要提供一个字符串形式的表达式就行了,那么adviceBeanName+expression就组成了切面

下面通过外观模式来实现切面,把Advice和Pointcut组合起来

  1. /**
  2. * @className: Advisor
  3. * @description: 构建切面的接口,组合advice和pointcut
  4. * @author: TR
  5. */
  6. public interface Advisor {
  7. /**
  8. * 获取通知bean的名称
  9. * @return: java.lang.String
  10. **/
  11. String getAdviceBeanName();
  12. /**
  13. * 获取切点表达式
  14. * @return: java.lang.String
  15. **/
  16. String getExpression();
  17. }
  1. /**
  2. * @className: PointcutAdvisor
  3. * @description: 切点通知者,继承自Advisor,扩展了pointcut
  4. * @author: TR
  5. */
  6. public interface PointcutAdvisor extends Advisor {
  7. /**
  8. * 获取切点
  9. * @return: PointCut
  10. **/
  11. PointCut getPointCut();
  12. }
  1. /**
  2. * @className: AspectJPointcutAdvisor
  3. * @description: AspectJ切点表达式的通知者实现类
  4. * @author: TR
  5. */
  6. public class AspectJPointcutAdvisor implements PointcutAdvisor {
  7. /** 通知bean的名称 */
  8. private String adviceBeanName;
  9. /** 表达式 */
  10. private String expression;
  11. /** 切点 */
  12. private PointCut pointCut;
  13. public AspectJPointcutAdvisor(String adviceBeanName, String expression) {
  14. this.adviceBeanName = adviceBeanName;
  15. this.expression = expression;
  16. this.pointCut = new AspectJExpressionPointcut(expression);
  17. }
  18. @Override
  19. public PointCut getPointCut() {
  20. return pointCut;
  21. }
  22. @Override
  23. public String getAdviceBeanName() {
  24. return adviceBeanName;
  25. }
  26. @Override
  27. public String getExpression() {
  28. return expression;
  29. }
  30. }

下面的类不予实现,主要使用AspactJ的形式

  1. /**
  2. * @className: RegPointcutAdvisor
  3. * @description: 正则切点表达式的通知者实现类
  4. * @author: TR
  5. */
  6. public class RegPointcutAdvisor implements PointcutAdvisor {
  7. /** 通知bean的名称 */
  8. private String adviceBeanName;
  9. /** 表达式 */
  10. private String expression;
  11. /** 切点 */
  12. private PointCut pointCut;
  13. public RegPointcutAdvisor(String adviceBeanName, String expression) {
  14. this.adviceBeanName = adviceBeanName;
  15. this.expression = expression;
  16. this.pointCut = new RegExpressionPointcut();
  17. }
  18. @Override
  19. public PointCut getPointCut() {
  20. return null;
  21. }
  22. @Override
  23. public String getAdviceBeanName() {
  24. return null;
  25. }
  26. @Override
  27. public String getExpression() {
  28. return null;
  29. }
  30. }

类图如下:
在这里插入图片描述

从上面的图中看到了,如果再扩展其他的切点表达式,那么在实现类中,可以看到,有很多的重复代码,那么是不是还可以优化一下呢,可以在实现类的上层再加一个抽象类,来继承PointcutAdvisor,然后主要的切点实现继承这个抽象类就行了

要完成的事情

将用户提供的增强功能加入到指定的方法上,需要我们来实现

什么时候做织入

在创建Bean实例的时候,在Bean初始化完成后,再进行织入

怎么知道Bean要进行增强

需要遍历Bean类及其所有的方法,然后依次的去匹配用户指定的切面,如果存在匹配的切面,就是需要增强了

怎么织入呢,就是需要用到代理了!
在这里插入图片描述
用户需要去注册切面,我们还需要实现判断匹配、织入的的逻辑,这部分代码改如何写,需要写到哪里呢

现在要做的事情,就是在Bean创建的过程中加一项处理,后面可能会在Bean的创建过程中加入更多的处理,如果这部分代码都写在BeanFactory中,那么这个类是不是就会有特别多的代码,而且后面不方便扩展

看下Bean的创建过程:
在这里插入图片描述
上面图中,每个箭头都是加的扩展点,后面可能存在的是,需要在这些点上加入更多的处理逻辑,那么就需要设计一种方式,在不改变BeanFactory的情况下,能灵活的扩展,那么可以使用观察者模式,有几个扩展点,就是有几个主题,六个观察者
在这里插入图片描述

  1. /**
  2. * @className: BeanPostProcessor
  3. * @description: 后置处理器,Bean实例化完成后及依赖注入完成后触发
  4. * @author: TR
  5. */
  6. public interface BeanPostProcessor {
  7. /**
  8. * bean初始化前的处理
  9. * @author: TR
  10. * @param bean: bean实例
  11. * @param beanName: bean名称
  12. * @return: java.lang.Object
  13. **/
  14. default Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
  15. return bean;
  16. }
  17. /**
  18. * bean初始化后的处理
  19. * @author: TR
  20. * @param bean: bean实例
  21. * @param beanName: bean名称
  22. * @return: java.lang.Object
  23. **/
  24. default Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
  25. return bean;
  26. }
  27. }
  1. /**
  2. * @className: Aware
  3. * @description: 构建通知接口
  4. * @date: 2021/4/19 16:38
  5. * @author: jinpeng.sun
  6. */
  7. public interface Aware {
  8. }
  1. /**
  2. * @className: BeanFactoryAware
  3. * @description: bean工厂构建通知接口
  4. * @author: TR
  5. */
  6. public interface BeanFactoryAware extends Aware {
  7. /**
  8. * 接口实现者获得bean工厂方法
  9. * @author: TR
  10. * @param bf:
  11. * @return: void
  12. **/
  13. void setBeanFactory(BeanFactory bf);
  14. }

上面的接口主要用来获得Bean工厂信息

这个接口主要用来把Advisor注册到增强功能的实现类里面

  1. /**
  2. * @className: AdvisorRegistry
  3. * @description: 通知者注册接口
  4. * @author: TR
  5. */
  6. public interface AdvisorRegistry {
  7. /**
  8. * 注册通知者
  9. * @author: TR
  10. * @param advisor:
  11. * @return: void
  12. **/
  13. public void registerAdvisor(Advisor advisor);
  14. /**
  15. * 获得通知者列表
  16. * @author: TR
  17. * @date: 2021/4/19 16:45
  18. *
  19. * @return: java.util.List<demo.aop.advisor.Advisor>
  20. **/
  21. public List<Advisor> getAdvisors();
  22. }
  1. /**
  2. * @className: AdvisorAutoProxyCreator
  3. * @description: 功能增强的实现类,用户和框架交互的核心类
  4. * 用户通过Advisor提供切面,向DefaultBeanFactory注入该实现
  5. * 框架内部:DefaultBeanFactory注入ioc容器
  6. * DefaultBeanFactory调用BeanPostProcessor接口相关方法,进行功能增强
  7. * @author: TR
  8. */
  9. public class AdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware, AdvisorRegistry {
  10. /** 通知者列表 */
  11. private List<Advisor> advisors;
  12. /** 当前的bean */
  13. private BeanFactory beanFactory;
  14. public AdvisorAutoProxyCreator() {
  15. this.advisors = new ArrayList<>();
  16. }
  17. @Override
  18. public void registerAdvisor(Advisor advisor) {
  19. this.advisors.add(advisor);
  20. }
  21. @Override
  22. public List<Advisor> getAdvisors() {
  23. return this.advisors;
  24. }
  25. @Override
  26. public void setBeanFactory(BeanFactory bf) {
  27. this.beanFactory = bf;
  28. }
  29. @Override
  30. public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
  31. return null;
  32. }
  33. }

BeanFactory接口中增加注册BeanPostProcessor的方法

  1. /** 注册BeanPostProcessor */
  2. void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor);

DefaultBeanFactory实现类中增加如下方法:

  1. private List<BeanPostProcessor> postProcessors = Collections.synchronizedList(new ArrayList<>());
  2. @Override
  3. public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
  4. postProcessors.add(beanPostProcessor);
  5. if (beanPostProcessor instanceof BeanFactoryAware) {
  6. ((BeanFactoryAware) beanPostProcessor).setBeanFactory(this);
  7. }
  8. }

getBean方法中增加bean初始化前后的处理:

  1. @Override
  2. public Object getBean(String beanName) throws Exception {
  3. //获取bean定义
  4. BeanDefinition bd = beanDefinitionMap.get(beanName);
  5. Object bean = doGetBean(beanName);
  6. //属性注入
  7. setPropertyDIValues(bd, bean);
  8. //bean初始化前的处理
  9. bean = this.applyPostProcessBeforeInitialization(bean, beanName);
  10. //bean的生命周期
  11. if (StringUtils.isNotBlank(bd.getInitMethodName())) {
  12. doInitMethod(bean,bd);
  13. }
  14. //bean初始化后的处理
  15. bean = this.applyPostProcessAfterInitialization(bean, beanName);
  16. return bean;
  17. }
  18. /**
  19. * bean初始化后的处理
  20. * @author: TR
  21. * @param bean:
  22. * @param beanName:
  23. * @return: java.lang.Object
  24. **/
  25. private Object applyPostProcessAfterInitialization(Object bean, String beanName) throws Exception {
  26. for (BeanPostProcessor bp : this.postProcessors) {
  27. bean = bp.postProcessBeforeInitialization(bean, beanName);
  28. }
  29. return bean;
  30. }
  31. /**
  32. * bean初始化前的处理
  33. * @author: TR
  34. * @param bean:
  35. * @param beanName:
  36. * @return: java.lang.Object
  37. **/
  38. private Object applyPostProcessBeforeInitialization(Object bean, String beanName) throws Exception {
  39. for (BeanPostProcessor bp : this.postProcessors) {
  40. bean = bp.postProcessAfterInitialization(bean, beanName);
  41. }
  42. return bean;
  43. }

下面需要实现的就是判断bean是否需要增强了,那么需要获取到bean的所有方法,然后根据注册进来的advisors去遍历它,然后得到切点去匹配类和方法

修改AdvisorAutoProxyCreator类中的postProcessAfterInitialization方法:

  1. @Override
  2. public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
  3. //判断是否需要进行切面增强,及获得增强的通知实现
  4. List<Advisor> advisors = getMatchedAdvisors(bean, beanName);
  5. //如果需要增强,返回增强后的对象
  6. if (CollectionUtils.isNotEmpty(advisors)) {
  7. //使用代理模式进行功能增强
  8. }
  9. return bean;
  10. }

下面是获取匹配的方法代码:

  1. /**
  2. * 获取匹配的方法
  3. * @author: TR
  4. * @param bean: bean实例
  5. * @param beanName: bean名称
  6. * @return: void
  7. **/
  8. private List<Advisor> getMatchedAdvisors(Object bean, String beanName) {
  9. if (CollectionUtils.isEmpty(advisors)) {
  10. return null;
  11. }
  12. //得到类
  13. Class<?> beanClass = bean.getClass();
  14. //得到所有的方法
  15. List<Method> allMethods = getAllMethodForClass(beanClass);
  16. //存放匹配的Advisor
  17. List<Advisor> advisors = new ArrayList<>();
  18. for (Advisor ad : this.advisors) {
  19. if (ad instanceof PointcutAdvisor) {
  20. //判断是否匹配
  21. if (isPointcutMatchBean((PointcutAdvisor) ad, beanClass, allMethods)) {
  22. advisors.add(ad);
  23. }
  24. }
  25. }
  26. return advisors;
  27. }

获取所有的方法,使用的是Spring framework提供的工具类,来找到类下面所有的方法:

  1. /**
  2. * 获取所有的方法
  3. * @author: TR
  4. * @param beanClass:
  5. * @return: void
  6. **/
  7. private List<Method> getAllMethodForClass(Class<?> beanClass) {
  8. List<Method> allMethods = new LinkedList<>();
  9. Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(beanClass));
  10. classes.add(beanClass);
  11. for (Class<?> cc : classes) {
  12. //根据工具类获取所有的方法
  13. Method[] methods = ReflectionUtils.getAllDeclaredMethods(cc);
  14. for (Method m : methods) {
  15. allMethods.add(m);
  16. }
  17. }
  18. return allMethods;
  19. }

下面是判断是否有匹配切点规则的方法,使用PointCut中定义的方法来实现:

  1. /**
  2. * 判断是否有匹配切点规则的方法
  3. * @author: TR
  4. * @param ad: 切面
  5. * @param beanClass: 指定的类
  6. * @param allMethods: 指定的类下面所有的方法
  7. * @return: void
  8. **/
  9. private boolean isPointcutMatchBean(PointcutAdvisor ad, Class<?> beanClass, List<Method> allMethods) {
  10. PointCut p = ad.getPointCut();
  11. //匹配类
  12. if (!p.matchClass(beanClass)) {
  13. return false;
  14. }
  15. for (Method m : allMethods) {
  16. //匹配方法
  17. if (p.matchMethod(m, beanClass)) {
  18. return true;
  19. }
  20. }
  21. return false;
  22. }

判断是否增强之后,就是需要进行代理增强了,那么这里的实现逻辑又是啥样的呢
在这里插入图片描述
通过上图可以看到,需要判断代理的方式,即使用JDK动态代理还是CGLIB动态代码,那么这里也可以抽象出一个接口。然后不同的代理方式分别去实现

  1. /**
  2. * @className: AopProxy
  3. * @description: AOP代理接口,用来创建和获取代理对象
  4. * @author: TR
  5. */
  6. public interface AopProxy {
  7. Object getProxy();
  8. Object getProxy(ClassLoader classLoader);
  9. }

我们知道JDK动态代理是对接口进行的,那么在实现中需要哪些数据呢?

  • 要实现的接口
  • 目标对象
  • 匹配的Advisors
  • BeanFactory

需要的参数:

  • 需要实现的接口
  • InvocationHandler
  1. /**
  2. * @className: JdkDynamicAopProxy
  3. * @description: JDK动态代理实现
  4. * @author: TR
  5. */
  6. public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
  7. private static final Logger logger = LoggerFactory.getLogger(JdkDynamicAopProxy.class);
  8. //bean名称
  9. private String beanName;
  10. //bean对象,需要被代理的对象
  11. private Object target;
  12. //通知列表,需要被增强的功能
  13. private List<Advisor> advisors;
  14. //当前的bean
  15. private BeanFactory beanFactory;
  16. public JdkDynamicAopProxy(String beanName, Object target, List<Advisor> advisors, BeanFactory beanFactory) {
  17. this.beanName = beanName;
  18. this.target = target;
  19. this.advisors = advisors;
  20. this.beanFactory = beanFactory;
  21. }
  22. @Override
  23. public Object getProxy() {
  24. return this.getProxy(target.getClass().getClassLoader());
  25. }
  26. @Override
  27. public Object getProxy(ClassLoader classLoader) {
  28. if (logger.isDebugEnabled()) {
  29. logger.debug("为" + target + "创建JDK代理。");
  30. }
  31. return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
  32. }
  33. /**
  34. * InvocationHandler接口的实现
  35. * 用来进行代理增强后返回实际的结果
  36. */
  37. @Override
  38. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  39. return AopProxyUtils.applyAdvices(target, method, args, advisors, proxy, beanFactory);
  40. }
  41. }

CGLIB动态代理可以对接口和类进行,那么它需要下面的数据:

  • 要继承的类
  • 要实现的接口
  • 目标对象
  • 匹配的Advisors
  • BeanFactory
  • 构造参数类
  • 构造参数

需要的参数:

  • 继承的类
  • 需要实现的接口
  • Callback
  • 构造参数类型
  • 构造参数

构造参数类型和构造参数在创建实例的时候会有的

  1. /**
  2. * @className: CglibDynamicAopProxy
  3. * @description: Cglib动态代理
  4. * @author: TR
  5. */
  6. public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {
  7. private static final Logger logger = LoggerFactory.getLogger(CglibDynamicAopProxy.class);
  8. private static Enhancer enhancer = new Enhancer();
  9. //bean名称
  10. private String beanName;
  11. //bean对象,需要被代理的对象
  12. private Object target;
  13. //通知列表,需要被增强的功能
  14. private List<Advisor> advisors;
  15. //当前的bean
  16. private BeanFactory beanFactory;
  17. public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> advisors, BeanFactory beanFactory) {
  18. this.beanName = beanName;
  19. this.target = target;
  20. this.advisors = advisors;
  21. this.beanFactory = beanFactory;
  22. }
  23. @Override
  24. public Object getProxy() {
  25. return this.getProxy(target.getClass().getClassLoader());
  26. }
  27. @Override
  28. public Object getProxy(ClassLoader classLoader) {
  29. if (logger.isDebugEnabled()) {
  30. logger.debug("为" + target + "创建cglib代理。");
  31. }
  32. Class<?> superClass = this.target.getClass();
  33. enhancer.setSuperclass(superClass);
  34. enhancer.setInterfaces(this.getClass().getInterfaces());
  35. enhancer.setCallback(this);
  36. Constructor<?> constructor = null;
  37. try {
  38. constructor = superClass.getConstructor(new Class<?>[] {});
  39. } catch (NoSuchMethodException e) {
  40. e.printStackTrace();
  41. }
  42. if (constructor != null) {
  43. return enhancer.create();
  44. } else {
  45. BeanDefinition bd = ((DefaultBeanFactory)beanFactory).getBeanDefinition(beanName);
  46. return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
  47. }
  48. }
  49. @Override
  50. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  51. return AopProxyUtils.applyAdvices(target, method, objects, advisors, o, beanFactory);
  52. }
  53. }

AopProxyUtils它是用来干什么的呢,从上面可以看到,这部分的处理,主要是用来实现增强的,都是使用Advice来增强的,所以增强的逻辑是一样的
在这里插入图片描述

  1. /**
  2. * @className: AopProxyUtils
  3. * @description: aop代理工具类
  4. * @author: TR
  5. */
  6. public class AopProxyUtils {
  7. /**
  8. * 对方法应用advice增强,获得最终返回结果
  9. * @author: TR
  10. * @param target: 需要被增强的对象
  11. * @param method: 需要被增强的方法
  12. * @param args: 增强方法的参数
  13. * @param advisors: 匹配到的切面
  14. * @param proxy: bean对象功能增强后的代理对象
  15. * @param beanFactory: bean工厂
  16. * @return: java.lang.Object
  17. **/
  18. public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> advisors,
  19. Object proxy, BeanFactory beanFactory) throws Throwable {
  20. //获取对当前方法进行增强的advices
  21. List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, advisors, beanFactory);
  22. if (CollectionUtils.isEmpty(advices)) {
  23. return method.invoke(target, args);
  24. } else {
  25. //使用责任链进行增强
  26. AopAdviceChainInvocation ac = new AopAdviceChainInvocation(proxy, target, method, args, advices);
  27. return ac.invoke();
  28. }
  29. }
  30. /**
  31. * 获得与方法匹配的Advice切面列表
  32. * @author: TR
  33. * @param aClass:
  34. * @param method:
  35. * @param advisors:
  36. * @param beanFactory:
  37. * @return: java.util.List<demo.aop.advice.Advice>
  38. **/
  39. private static List<Object> getShouldApplyAdvices(Class<?> aClass, Method method,
  40. List<Advisor> advisors, BeanFactory beanFactory) throws Exception {
  41. if (CollectionUtils.isEmpty(advisors)) {
  42. return null;
  43. }
  44. List<Object> advices = new ArrayList<>();
  45. for (Advisor advisor : advisors) {
  46. if (advisor instanceof PointcutAdvisor) {
  47. if (((PointcutAdvisor)advisor).getPointCut().matchMethod(method, aClass)) {
  48. advices.add(beanFactory.getBean(advisor.getAdviceBeanName()));
  49. }
  50. }
  51. }
  52. return advices;
  53. }
  54. }

如何来传递创建bean实例时获得的数据到初始化后的Aop中,就是要在BeanDefinition中使用ThreadLocal持有参数值

BeanDefinition增加如下方法:

  1. /** 获取构造参数值 */
  2. public Object[] getConstructorArgumentRealValues();
  3. /** 设置构造参数值 */
  4. public void setConstructorArgumentRealValues(Object[] values);

GeneralBeanDefinition类中相应的实现:

  1. private ThreadLocal<Object[]> realConstructorArgumentValues = new ThreadLocal<>();
  2. @Override
  3. public Object[] getConstructorArgumentRealValues() {
  4. return realConstructorArgumentValues.get();
  5. }
  6. @Override
  7. public void setConstructorArgumentRealValues(Object[] values) {
  8. this.realConstructorArgumentValues.set(values);
  9. }
  1. /**
  2. * @className: AopAdviceChainInvocation
  3. * @description: AOP责任链调用类
  4. * @author: TR
  5. */
  6. public class AopAdviceChainInvocation {
  7. /** AOP责任链执行的方法 */
  8. private static Method invokeMethod;
  9. static {
  10. try {
  11. invokeMethod = AopAdviceChainInvocation.class.getMethod("invoke", null);
  12. } catch (NoSuchMethodException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. //代理类对象
  17. private Object proxy;
  18. //目标类对象
  19. private Object target;
  20. //调用执行的对象方法
  21. private Method method;
  22. //执行方法的参数
  23. private Object[] args;
  24. //方法被增强的功能:通知列表
  25. private List<Object> advices;
  26. public AopAdviceChainInvocation(Object proxy, Object target, Method method, Object[] args, List<Object> advices) {
  27. this.proxy = proxy;
  28. this.target = target;
  29. this.method = method;
  30. this.args = args;
  31. this.advices = advices;
  32. }
  33. //责任链执行记录的索引号
  34. private int i = 0;
  35. public Object invoke() throws Throwable {
  36. if (i < this.advices.size()) {
  37. Object advice = this.advices.get(i++);
  38. if (advice instanceof MethodBeforeAdvice) {
  39. //执行前增强
  40. ((MethodBeforeAdvice)advice).before(method, target, args);
  41. } else if (advice instanceof MethodInterceptor) {
  42. //执行环绕增强和异常增强,这里给的method和对象是invoke方法和链对象
  43. ((MethodInterceptor)advice).invoke(invokeMethod,this, null);
  44. } else if (advice instanceof AfterReturningAdvice) {
  45. //后置增强,先获得结果,在增强
  46. Object returnValue = this.invoke();
  47. ((AfterReturningAdvice)advice).after(method, target, args, returnValue);
  48. return returnValue;
  49. }
  50. //回调
  51. return this.invoke();
  52. } else {
  53. return method.invoke(target, args);
  54. }
  55. }
  56. }

代理的方式实现完了之后,就需要使用它了,这里使用工厂模式实现:

  1. /**
  2. * @className: AopProxyFactory
  3. * @description: AOP代理的工厂接口
  4. * @author: TR
  5. */
  6. public interface AopProxyFactory {
  7. /**
  8. * 根据参数获取AOP代理接口的实现
  9. * @param bean: 实例
  10. * @param beanName: bean名称
  11. * @param advisors: advisors列表
  12. * @param beanFactory: bean工厂
  13. * @return: AopProxyFactory
  14. **/
  15. AopProxy createAopProxy(Object bean, String beanName, List<Advisor> advisors, BeanFactory beanFactory);
  16. /**
  17. * 获取默认的AopProxyFactory
  18. * @return: AopProxyFactory
  19. **/
  20. static AopProxyFactory getDefaultAopProxyFactory() {
  21. return new DefaultAopProxyFactory();
  22. }
  23. }

实现类:

  1. /**
  2. * @className: DefaultAopProxyFactory
  3. * @description: 代理工厂实现类
  4. * @author: TR
  5. */
  6. public class DefaultAopProxyFactory implements AopProxyFactory {
  7. @Override
  8. public AopProxy createAopProxy(Object bean, String beanName, List<Advisor> advisors, BeanFactory beanFactory) {
  9. //是用JDK动态代理还是CGLIB动态代理
  10. if (shouldUseJDKDynamicProxy(bean, beanName)) {
  11. return new JdkDynamicAopProxy(beanName, bean, advisors, beanFactory);
  12. } else {
  13. return new CglibDynamicAopProxy(beanName, bean, advisors, beanFactory);
  14. }
  15. }
  16. private boolean shouldUseJDKDynamicProxy(Object bean, String beanName) {
  17. return false;
  18. }
  19. }

下面需要修改下AdvisorAutoProxyCreator类中的postProcessAfterInitialization方法:

  1. @Override
  2. public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
  3. //判断是否需要进行切面增强,及获得增强的通知实现
  4. List<Advisor> advisors = getMatchedAdvisors(bean, beanName);
  5. //如果需要增强,返回增强后的对象
  6. if (CollectionUtils.isNotEmpty(advisors)) {
  7. //使用代理模式进行功能增强
  8. bean = this.createProxy(bean, beanName, advisors);
  9. }
  10. return bean;
  11. }
  12. private Object createProxy(Object bean, String beanName, List<Advisor> advisors) {
  13. return AopProxyFactory.getDefaultAopProxyFactory()
  14. .createAopProxy(bean, beanName, advisors, beanFactory)
  15. .getProxy();
  16. }

DefaultBeanFactory类中缓存构造函数的方式需要改变一下

determineConstructor方法中缓存的代码注释掉:

  1. if (ct != null) {
  2. // //对于原型bean,缓存起来
  3. // if (bd.isProtoType()) {
  4. // bd.setConstructor(ct);
  5. // }
  6. return ct;
  7. } else {
  8. throw new Exception("找不到对应的构造方法:" + bd);
  9. }

在createBeanByConstructor中增加代码

  1. /** 通过构造函数构建bean */
  2. private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
  3. Object object = null;
  4. if (CollectionUtils.isEmpty(bd.getConstructorArgumentValues())) {
  5. //获得的构造参数值是空的,就不传参
  6. object = bd.getBeanClass().newInstance();
  7. } else {
  8. //获得的参数值是空的,就不传参
  9. Object[] args = getConstructorArgumentValues(bd);
  10. if (args == null) {
  11. object = bd.getBeanClass().newInstance();
  12. } else {
  13. // 根据参数匹配决定构造方法,然后进行实例化调用
  14. bd.setConstructorArgumentRealValues(args);
  15. Constructor<?> ct = this.determineConstructor(bd, args);
  16. // 缓存构造函数由determineConstructor 中移到了这里,无论原型否都缓存,因为后面AOP需要用
  17. bd.setConstructor(ct);
  18. return ct.newInstance(args);
  19. }
  20. }
  21. return object;
  22. }

前置增强实现:

  1. public class MyBeforeAdvice implements MethodBeforeAdvice {
  2. @Override
  3. public void before(Method method, Object target, Object[] args) {
  4. System.out.println(this + " 对 " + target + " 进行了前置增强!");
  5. }
  6. }

后置增强实现:

  1. public class MyAfterReturningAdvice implements AfterReturningAdvice {
  2. @Override
  3. public void after(Method method, Object target, Object[] args, Object returnValue) {
  4. System.out.println(this + " 对 " + target + " 做了后置增强,得到的返回值=" + returnValue);
  5. }
  6. }

环绕增强实现:

  1. public class MyMethodInterceptor implements MethodInterceptor {
  2. @Override
  3. public Object invoke(Method method, Object target, Object[] args) throws Throwable {
  4. System.out.println(this + "对 " + target + "进行了环绕--前增强");
  5. Object ret = method.invoke(target, args);
  6. System.out.println(this + "对 " + target + "进行了环绕 --后增强。方法的返回值为:" + ret);
  7. return ret;
  8. }
  9. }

测试类:

  1. public class AopTest {
  2. static PreBuildBeanFactory bf = new PreBuildBeanFactory();
  3. @Test
  4. public void testCirculationDI() throws Throwable {
  5. GeneralBeanDefinition bd = new GeneralBeanDefinition();
  6. bd.setBeanClass(Lad.class);
  7. List<Object> args = new ArrayList<>();
  8. args.add("孙悟空");
  9. args.add(new BeanReference("baigujing"));
  10. bd.setConstructorArgumentValues(args);
  11. bf.registerBeanDefinition("swk", bd);
  12. bd = new GeneralBeanDefinition();
  13. bd.setBeanClass(MagicGirl.class);
  14. args = new ArrayList<>();
  15. args.add("白骨精");
  16. bd.setConstructorArgumentValues(args);
  17. bf.registerBeanDefinition("baigujing", bd);
  18. bd = new GeneralBeanDefinition();
  19. bd.setBeanClass(Renminbi.class);
  20. bf.registerBeanDefinition("renminbi", bd);
  21. // 前置增强advice bean注册
  22. bd = new GeneralBeanDefinition();
  23. bd.setBeanClass(MyBeforeAdvice.class);
  24. bf.registerBeanDefinition("myBeforeAdvice", bd);
  25. // 环绕增强advice bean注册
  26. bd = new GeneralBeanDefinition();
  27. bd.setBeanClass(MyMethodInterceptor.class);
  28. bf.registerBeanDefinition("myMethodInterceptor", bd);
  29. // 后置增强advice bean注册
  30. bd = new GeneralBeanDefinition();
  31. bd.setBeanClass(MyAfterReturningAdvice.class);
  32. bf.registerBeanDefinition("myAfterReturningAdvice", bd);
  33. // 往BeanFactory中注册AOP的BeanPostProcessor
  34. AdvisorAutoProxyCreator aapc = new AdvisorAutoProxyCreator();
  35. bf.registerBeanPostProcessor(aapc);
  36. // 向AdvisorAutoProxyCreator注册Advisor
  37. aapc.registerAdvisor(
  38. new AspectJPointcutAdvisor("myBeforeAdvice", "execution(* demo.di.MagicGirl.*(..))"));
  39. // 向AdvisorAutoProxyCreator注册Advisor
  40. aapc.registerAdvisor(
  41. new AspectJPointcutAdvisor("myMethodInterceptor", "execution(* demo.di.Lad.say*(..))"));
  42. // 向AdvisorAutoProxyCreator注册Advisor
  43. aapc.registerAdvisor(new AspectJPointcutAdvisor("myAfterReturningAdvice",
  44. "execution(* demo.di.Renminbi.*(..))"));
  45. bf.preInstantiateSingletons();
  46. System.out.println("-----------------myBeforeAdvice---------------");
  47. MagicGirl gril = (MagicGirl) bf.getBean("baigujing");
  48. gril.getFriend();
  49. gril.getName();
  50. System.out.println("----------------myMethodInterceptor----------------");
  51. Boy boy = (Boy) bf.getBean("swk");
  52. boy.sayLove();
  53. System.out.println("-----------------myAfterReturningAdvice---------------");
  54. Renminbi rmb = (Renminbi) bf.getBean("renminbi");
  55. rmb.pay();
  56. }
  57. }

运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
本文其他知识点:

版权声明:本文为fox2said原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/fox2said/p/14686800.html