【Spring】AOP的作用和底层原理、AOP相关术语

文章目录

一、AOP 概述

AOP: 全称是Aspect Oriented Programming,即:面向切面编程。它把程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对已有方法进行增强。
【Spring】AOP的作用和底层原理、AOP相关术语

作用: 在程序运行期间,不修改源码对已有方法进行增强
优势: 减少重复代码、提高开发效率、维护方便、
实现方式: 使用动态代理技术

二、动态代理

字节码随用随创建,随用随加载。静态代理是字节码一上来就创建好,并完成加载。装饰者模式就是静态代理的一种体现。

动态代理常用的有两种方式:

  • 基于接口的动态代理
    • 提供者: JDK 官方的Proxy类。
    • 要求: 被代理类最少实现一个接口。
  • 基于子类的动态代理
    • 提供者: 第三方的CGLIB,如果报 asmxxxx 异常,需要导入asm.jar
    • 要求: 被代理类不能用 final 修饰的类(最终类)。

三、使用JDK动态代理

使用java.lang.reflect.Proxy类里面的newProxyInstance()方法创建代理对象

方法介绍:

  • newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
    • ClassLoader loader:定义代理类的类加载器
    • Class<?>[] interfaces:代理类要实现的接口列表,支持多个接口
    • InvocationHandler h:实现InvocationHandler接口,创建代理对象,写增强的方法。

第一步: 创建一个接口,待增强的接口

public interface UserDao {
    public int add(int a, int b);
    public String update(String id);
}

第二步: 创建接口实现类,并实现方法

public class UserDaoImpl implements UserDao {
    @Override
    public int add(int a, int b) {
    	System.out.println("add方法执行了...");
        return a + b;
    }

    @Override
    public String update(String id) {
    	System.out.println("update方法执行了...");
        return id;
    }
}

第三步: 创建JDK的接口实现类代理对象

UserDaoProxy类在第四步

public class JDKProxy {
    public static void main(String[] args) {
        // 创建jdk的代理对象
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
    }
}

第四步: 创建代理对象

class UserDaoProxy implements InvocationHandler {
    // 增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

第五步: 将需要增强的对象传递进来

class UserDaoProxy implements InvocationHandler {
    
    // 这是谁的代理对象,就把谁传递进来
    // 可以使用有参构造传递,这里使用Object可以更通用一点,只要是UserDao的实现类都可以传入
    public UserDaoProxy(Object obj) {
        this.obj = obj;
    } 
    
    private Object obj;
    
    // 增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

第六步: 编写增强代码的逻辑

class UserDaoProxy implements InvocationHandler {

    // 这是谁的代理对象,就把谁传递进来
    // 可以使用有参构造传递,这里使用Object可以更通用一点,只要是UserDao的实现类都可以传入
    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }

    private Object obj;

    // 增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 方法执行之前的操作
        System.out.println("方法执行之前的操作...." + method.getName() + ":传递的参数..." + Arrays.toString(args));

        // 方法执行
        Object res = method.invoke(obj, args);

        // 方法执行之后的操作
        System.out.println("方法执行之后的操作...." + obj + ",方法的返回值:" + res);

        // 将方法的返回值返回
        return res;
    }
}

第七步: 调用增强方法

public class JDKProxy {
    public static void main(String[] args) {
        // 创建jdk的代理对象
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        int res = dao.add(1, 5);
        System.out.println("测试时方法的返回值为:" + res);
    }
}

可以得到结果:
【Spring】AOP的作用和底层原理、AOP相关术语

四、AOP相关术语

Joinpoint(连接点)

指被拦截到的点。在spring中,指的是方法,因为spring只支持方法类型的连接点。
简单地说:类里面哪些方法可以被增强,就称为连接点。

Pointcut(切入点)

指要进行拦截的Joinpoint的定义。
通俗地说:实际上被增强的方法,就称为切入点。

Advice(通知/增强)

指拦截到Joinpoint之后所要做的事情。
实际增强的逻辑部分,就叫做通知(增强)

通知的类型:
前置通知:被增强的方法执行之前的通知
后置通知:被增强的方法执行之后的通知
异常通知:被增强的方法出现异常后的通知
最终通知:不管有没有异常都会执行,类似于异常的finally
环绕通知:被增强的方法执行之前之后都做的通知

Aspect(切面)

是切入点和通知(引介)的结合。
简单地说:把通知应用到切入点的过程

Introduction(引介)

是一种特殊的通知,在不修改类代码的前提下,可以在运行期为类动态地添加一些方法或Field。

Target(目标对象)

代理的目标对象。

Weaving(织入)

把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

Proxy(代理)

一个类被AOP织入增强后,就产生一个结果代理类。

Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

上一篇:Spring Aop基于注解&Xml


下一篇:Spring Boot MyBatis 连接数据库