【Spring】AOP的理解——代理增强

什么是AOP

Aspect Oriented Programming,面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP是OOP的延续,是函数式编程的一种衍生。利用AOP可以对业务逻辑的各个部分进行隔离(即解耦),从而提高程序的可重用性。

 
 

作用及其优势

1)在程序运行期间,在不修改源码的情况下对方法进行功能增强

2)减少重复代码,提高开发效率,便于后期维护

 
 

彻底理解AOP

想象一下,B、C、D方法中都需要绑定一个A方法使用,我们进行一个无脑的重用(AB、AC、AD),这样会有什么坏处?

耦合过高,修改困难。如果我们想要修改A方法的一个细节,需要找到这三处方法(B、C、D)进行修改。因此我们想到了一个最朴素的解耦思想——抽取,即在B、C、D只进行抽取出的重复部分(A)的调用,这样在修改时仅仅需要修改一处。

但是,A与B、C、D,真的完全独立了吗?真的完全解耦了吗?

并没有。归根结底A与B(C、D)在代码层面还是绑定在一起的。
 
类的生命分为三个阶段——Source源代码阶段,Class类对象阶段,Runtime运行时阶段。我们仅仅需要让A与B(C、D)在 运行时阶段 即在内存中绑定在一起,而不需要在 源代码阶段 就绑定在一起不是吗?而我们可以“做手脚”的地方,正是 类对象阶段

在类对象阶段对成员变量(Field)、构造方法(Constructor)、成员方法(Method)这些对象的操作,是反射的本质。反射又是框架设计的灵魂。
 
至此,究竟什么是切面呢?就是这些在源代码阶段还未绑定、在运行时阶段已经绑定的方法。比如,AB就是一个切面。

上面的话可能在定义方面需要修正,但在理解方面无比正确且重要。

 
 

底层实现

AOP的底层是通过Spring提供的动态代理技术实现的。

在运行期间,Spring通过动态代理技术动态地生成代理对象,代理对象方法执行时进行功能增强的介入,再去调用目标对象的方法。

常用的动态代理技术有两种:

① 基于接口的JDK代理

② 基于父类的cglib代理

在这里插入图片描述

 
 

JDK代理

目标类接口 ----------------------------------------------------------------------------------
public interface TargetInterface {
    
    
    public void sayHi();
}


目标类 -------------------------------------------------------------------------------------
public class Target implements TargetInterface {
    
    

    public void sayHi() {
    
    
        System.out.println("目标方法 is runnig...");
    }
}


增强类 -------------------------------------------------------------------------------------
public class Enhance {
    
    

    public void enhanceBefore() {
    
    
        System.out.println("前置增强方法 is running...");
    }

    public void enhanceAfter() {
    
    
        System.out.println("后置增强方法 is running...");
    }
}


代理及其测试 --------------------------------------------------------------------------------
public class SpringTest {
    
    

    @Test
    public void test() {
    
    

        // 目标对象
        final Target target = new Target();

        // 增强对象
        final Enhance enhance = new Enhance();

        // 代理对象
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
    
    
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                        enhance.enhanceBefore();
                        Object invoke = method.invoke(target, args);
                        enhance.enhanceAfter();
                        return invoke;
                    }
                }
        );

        // 代理对象调用方法
        proxy.sayHi();

    }
}

在这里插入图片描述

 
 

cglib代理

目标类 -------------------------------------------------------------------------------------
public class Target {
    
    

    public void sayHi() {
    
    
        System.out.println("目标方法 is runnig...");
    }
}


增强类 -------------------------------------------------------------------------------------
public class Enhance {
    
    

    public void enhanceBefore() {
    
    
        System.out.println("前置增强方法 is running...");
    }

    public void enhanceAfter() {
    
    
        System.out.println("后置增强方法 is running...");
    }
}


代理及其测试 --------------------------------------------------------------------------------
public class SpringTest {
    
    

    @Test
    public void test() {
    
    

        // 目标对象
        final Target target = new Target();

        // 增强对象
        final Enhance enhance = new Enhance();

        // 1.创建增强器
        Enhancer enhancer = new Enhancer();
        // 2.设置父类(即目标)
        enhancer.setSuperclass(Target.class);
        // 3.设置回调
        enhancer.setCallback(new MethodInterceptor() {
    
    
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
                enhance.enhanceBefore();
                Object invoke = method.invoke(target, objects);
                enhance.enhanceAfter();
                return invoke;
            }
        });
        // 4.创建代理对象
        Target proxy = (Target) enhancer.create();

        // 代理对象调用方法
        proxy.sayHi();

    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_46202073/article/details/113878017