Spring|Spring AOP 基础概念

Pointcut 切入点
pointcut是spring独有,非aop联盟定义。
pointcut定义描述匹配某个或某些类的方法。相当于把某个类或某些类的方法抽取出来一起描述。
pointcut独立于增强点(advice)之外,可重复使用,即一个切入点可以被不同的advice使用。
实现由多种

  • 表达式匹配, 即定义表达式的方式匹配出切入点
  • 控制流式,比如声明一个切入点,指定谁调用才触发增强, 其他方式调用不触发增强.
  • 注解匹配等待
Advice 增强点
advice是aop联盟定义的,同时定义了interceptor为advice的子接口. 在spring中每个advice都是spring bean. 增强类型包括
  • 前置增强
  • 异常增强
  • 后置增强
  • 环绕增强
  • 引入增强
    引入增强(introduction advice)spring把引入增强视为一种特殊的增强拦截, 它为类添加一些属性和方法。引入增强不能和pointcut组合,引入增强只能作用于类,不能作用于方法上。
    这样,即一个业务类原本没有实现某个接口,通过引介功能,可以动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
Advisor 增强指导
spring中Advisor是一个advice关联一个pointcut的组合描述对象。
ProxyFactory 代理工厂
【Spring|Spring AOP 基础概念】提供创建代理对象的工厂,依赖Advisor
通过示例加深理解
定义 两个环绕增强,对目标类进行增强
  • 定义环绕增强, 即定义Advice对象。 MethodInterceptor是Advice的子类
public class AroundAdvise implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("before"); Object retVal = invocation.proceed(); System.out.println("after"); return retVal; } }

另一个环绕增强
public class AnotherAroundAdvise implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println(" another before"); Object retVal = invocation.proceed(); System.out.println(" another after"); return retVal; } }

  • 定义目标类,即被增强对象
public class NameMatchMethodTargetBean { public void run() { System.out.println("--- NameMatchMethodTargetBean running ---"); } }

  • 定义pointcut 并组合增强点,后创建代理对象
// 定义根据名称匹配的pointcut NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); // 指定匹配名称为run的方法 pointcut.addMethodName("run"); // 目标代理对象 NameMatchMethodTargetBean targetBean = new NameMatchMethodTargetBean(); // 增强点 Advice advice = new AroundAdvise(); Advice another = new AnotherAroundAdvise(); // 组合切入点合增强点 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); Advisor anotherAdvisor = new DefaultPointcutAdvisor(pointcut, another); // 生成代理对象 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addAdvisor(advisor); proxyFactory.addAdvisor(anotherAdvisor); proxyFactory.setTarget(targetBean); NameMatchMethodTargetBean proxyBean = (NameMatchMethodTargetBean) proxyFactory.getProxy(); proxyBean.run();

得到的结果
before another before --- NameMatchMethodTargetBean running --- another after after

从以上示例可以看出, 切入点合增强点是独立的,可以组合在一起。 增强点加入ProxyFactory后由list维护,list的顺序决定了advice的触发顺序.
流式切入点
流式切入点的功能是,指定从特定的类方法的调用才触发增强,其他方式调用不会触发。
  • 切入点使用上一个示例的代码
  • 目标类也使用上一个示例的代码,并添加多一个方法
public void run() { System.out.println(" target bean is running "); }

  • 定义流式切入点,并触发
public class StartUp {public static void main(String[] args) { TargetBean targetBean = new TargetBean(); // 定义切入点pointcut Pointcut pc = new ControlFlowPointcut(StartUp.class, "runFun"); // 增强点 Advice advice = new SimpleAdvise(); // 组合切入点和增强点 Advisor advisor = new DefaultPointcutAdvisor(pc, advice); // 创建代理 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addAdvisor(advisor); proxyFactory.setTarget(targetBean); TargetBean proxy = (TargetBean) proxyFactory.getProxy(); // 直接调用 proxy.run(); System.out.println("--------------------"); // 控制流式调用 runFun(proxy); }public static void runFun(TargetBean targetBean) { targetBean.run(); } }

运行结果
target bean is running -------------------- before target bean is running after

可以看到,直接调用代理对象的方法是不会触发增强点,需要通过流式切入点声明的对象方法才能触发增强.
引入增强示例
  • 定义需要引入的功能, 这里定义一个接口,使目标类由该接口的功能
public interface IntroductionInterface { void doSomething(); }

  • 定义引入增强
/** * 引入增强, 使被增强者 实现了 IntroductionInterface接口 */ public class IntroductionAdvise extends DelegatingIntroductionInterceptor implements IntroductionInterface { @Override public void doSomething() { System.out.println("你已被我增强!"); } }

这样就定义完成了, 这里对上一个示例的目标类NameMatchMethodTargetBean进行增强
// 引入增强 Advice introductionAdvice = new IntroductionAdvise(); // 引入增强不能和pointcut使用 Advisor introductionAdvisor = new DefaultIntroductionAdvisor(introductionAdvice); // 生成代理对象,代理对象即是targetBean也是IntroductionInterface ProxyFactory newProxyFactory = new ProxyFactory(); newProxyFactory.addAdvisor(introductionAdvisor); newProxyFactory.setTarget(targetBean); Object newProxyBean = newProxyFactory.getProxy(); if (newProxyBean instanceof IntroductionInterface) { ((IntroductionInterface) newProxyBean).doSomething(); }

以上即完成了对目标类NameMatchMethodTargetBean 引入了IntroductionInterface
ProxyFactoryBean
请看 https://www.jianshu.com/p/857c8cdf99c6
ProxyFactory
请看文字开头的示例
auto-proxy 自动开启代理
请看https://www.jianshu.com/p/b2f3f3058652
TargetSource
指的是被代理原始对象, spring中代理对象触发方法最终都会请求原始对象方法.
通常情况下不用关心原始对象. 不过可以通过这个特性实现特殊效果
对象池: 因为每次都会触发原始对象,那么就可以每次触发返回的原始对象都不一样。
热更新: 在线更新掉原始对象。
自定义增强类型
总结 aop是一种编程理念,spring的aop由自己规定的名词,也有aop联盟的规范。
只有了解定义名词的用途和边界,才能对aop做进一步的理解。
https://www.jianshu.com/p/b2f3f3058652

    推荐阅读