美文网首页
Spring AOP 基础概念

Spring AOP 基础概念

作者: 何德何能者 | 来源:发表于2021-01-12 15:05 被阅读0次

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 代理工厂

提供创建代理对象的工厂,依赖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

相关文章

网友评论

      本文标题:Spring AOP 基础概念

      本文链接:https://www.haomeiwen.com/subject/sfzsaktx.html