Spring框架的AOP

作者:陆金龙    发表时间:2022-04-06 19:48   

关键词:AspectJ  动态代理  InvocationHandler  

AOP就是实现横切的工具。有静态和动态两种不同的AOP。Spring AOP实现了其他完整的AOP实现的部分功能。

1.AOP相关概念

连接点(JointPoint):用来定义在程序的哪里通过AOP加入新的逻辑。典型的联结点有:调用一个方法、类初始化、对象初始化等。

通知(Advice):在某特定的连接点处运行的代码称为通知。有在连接点之前执行的前置通知、在连接点之后执行的后置通知等。

切入点(PointCut):切入点是一组连接点,定义某一个通知该何时执行。例如一个典型的连接点是方法调用,一个典型的切入点是对某一个类所有方法调用的集合。

织入(Weaving):将切面真正加入程序代码的过程。静态AOP织入是在编译时完成,动态AOP则是在程序运行时动态织入的。

切面(Aspect):通知和切入点的组合叫做切面,定义了一段程序中应该包含的逻辑,以及何时执行该逻辑。

目标(Target):执行过程中受AOP影响的对象,也被称为被通知对象。

2.AOP种类

AOP有两种不同的种类:静态AOP,比如AspectJ中,横切逻辑是在编译时加入到程序中的,修改横切需要重新编译代码;动态AOP,比如Spring AOP,横切逻辑是在运行时动态加入程序中的,无需重新编译代码就可以修改横切逻辑。

静态AOP通过直接对字节码进行操作,包括修改代码和扩展类,来完成织入过程。

动态AOP是在运行时动态完成,织入具体实现各有不同。Spring AOP采取的方法时建立代理,代理在适当的时候执行通知。

动态AOP的弱点在于性能一般不如静态AOP,优点在于可以随意修改程序的所有切面而无需重新编译。

3.Spring AOP

Spring里的连接点:Spring AOP最明显的简化之一是只支持一种连接点:方法调用。

Spring里的切面:由一个实现Advisor(通知者)接口的类表示的。

Spring支持五种不同的通知:前置通知(MethodBeforeAdvice)、后置通知(AfterReturningAdvide)、包围通知(MethodInterceptor)、抛出通知(ThrowAdvice)、引入通知(IntroductionInterceptor)。

4.Spring AOP实现原理

Spring AOP 逻辑上分为两部分:一是与Spring其他部分相对独立的AOP核心,一是让程序中使用AOP变得简单的框架服务。

代理是Spring AOP的重要组成部分。有两种不同的代理:JDK动态代理和CGLIB。

Spring AOP实现原理,使用动态代理实现,用代理对象替代对象。示例代码如下:

public class AProxy(){

    private A target;

    public AProxy(A target){

         this.target = target;

    }

    public A getProxy(){

         A proxy = null;

        ClassLoader loader = target.getClass().getClassLoader();

        Class[] interfaces = new Class[]{A.Class};

        InvocationHandler handler = new InvocationHandler(){

            @Override

            public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{

                System.out.println("the method is "+method.getName());

                 // 可以在这里实现前置通知

                Object result = method.invoke(target,args);

                 // 可以在这里实现后置通知

                System.out.println("the result is "+result.toString());

                return result;

            }

        }

        proxy = (A)Proxy.newProxyInstance(loader,interfaces,handler);

        return proxy;

    }

}