SpringBoot实战:Spring AOP动态代理和静态代理


一、代理的概念

Spring AOP(面向切面编程)是Spring框架的一个强大的特性,它实现了AOP的统一解决方案,是用来解决模块之间的解耦度,增强代码可维护性以及复用性。

通过AOP,可以在不修改基本业务代码的情况下,为程序添加额外的功能,如日志记录、事务管理、安全检查等。

Spring AOP为开发者提供了一种统一解决各种横切关注点的方法。这些横切关注点包括但不限于:
  1. 拦截器(Interceptors):Spring AOP允许开发者定义拦截器,这些拦截器可以在方法执行前后或抛出异常时执行特定的逻辑。例如,可以在服务层方法调用前后自动执行日志记录,而无需在每个方法中显式编写日志代码。
  2. 适配器(Adapters):虽然传统意义上的适配器模式并不直接由Spring AOP提供,但AOP的思想可以用于构建灵活的、可重用的适配器组件,特别是当这些适配器需要处理跨多个组件的横切关注点时。AOP使得适配器能够专注于其核心职责,同时允许其他关注点(如安全、日志等)通过切面(Aspect)来透明地添加。
  3. 统一结果返回:利用AOP,可以定义一个切面来统一处理服务层或控制器层方法的返回值。这个切面可以在方法执行完毕后,根据业务需求对返回值进行统一处理,如封装成统一格式的响应体返回给客户端。
  4. 统一异常处理:Spring AOP使得开发者能够定义一个全局的异常处理切面,该切面能够捕获并处理来自应用程序中多个部分的异常。这种方式避免了在每个方法中重复编写异常处理代码,提高了代码的整洁性和可维护性。
  5. 统一通知处理:AOP中的“通知”(Advice)是切面中的一个关键部分,它定义了切面的具体行为。通过定义不同类型的通知(如前置通知、后置通知、环绕通知等),开发者可以实现对方法调用的精确控制,并在方法调用的不同阶段执行统一的逻辑。

二、什么是代理模式?

举个例子:例如一些朋友可能通过在一些线上平台租房子,那么这个平台就是我们和房子之间的纽带。平台能够帮我们寻找要出租的房子,并对房子进行出租价格的评定。这就是代理模式。

SpringBoot实战:Spring AOP动态代理和静态代理

代理可分为静态代理和动态代理:

静态代理与动态代理的主要区别在于:它们的代理对象生成方式和灵活性。具体来说,静态代理的代理对象是在编译时期就明确指定并实现的,一旦编写完成,代理关系就固定下来,不会随着程序运行时的条件改变而变化。这种方式下,代理类和被代理类通常有着明确的对应关系,且需要手动编写代理类的代码。
而动态代理,正如其名,它的代理对象是在程序运行时动态生成的。这种动态性源于代理类的创建和代理行为的实现都不是在编译时期确定的,而是由系统在运行时根据需要自动完成的。动态代理通常依赖于一些动态代理技术或框架(如Java中的JDK动态代理或CGLIB等)来实现,这些技术能够在运行时根据接口或类的信息动态生成代理类的字节码,并加载到JVM中。

动态代理(主要是通过反射来完成的代理模式)

三、静态代理

由程序员创建代理类或特定⼯具⾃动⽣成源代码再对其编译,在程序运⾏前代理类的.class⽂件就已经存在了

public class HouseProxy implements HouseSubject{

  //将被代理对象声明为成员变量
  private HouseSubject houseSubject;
  
  public HouseProxy(HouseSubject houseSubject) {
    this.houseSubject = houseSubject;
  }
  
  @Override
  public void rentHouse() {
  
    //开始代理
    System.out.println("我是中介, 开始代理");
    
    //代理房东出租房⼦
    houseSubject.rentHouse();
    
    //代理结束
    System.out.println("我是中介, 代理结束");
  }
}

四、JDK代理

JDK代理,也称为基于接口的动态代理,是Java动态代理的一种实现方式,它要求被代理的对象必须实现一个或多个接口。JDK代理主要利用了java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来生成代理对象。
当你通过JDK代理创建代理对象时,你需要提供一个实现了InvocationHandler接口的类,该类中的invoke方法会拦截并处理所有通过代理对象调用的方法。Proxy类则负责生成代理类的实例。
下面是一个JDK代理的简单示例:
假设我们有一个接口Subject和两个实现了该接口的类RealSubject(被代理的类)和ProxySubject(代理类,但这里我们不直接实现它,而是通过动态代理来生成)。
// 定义一个接口 
interface Subject {
    void request();
}
  
// 被代理的类
class RealSubject implements Subject {
    @Override  
    public void request() {
        System.out.println("Called RealSubject.request()");
    }
}
  
// 实现InvocationHandler接口来定义代理的行为
class MyInvocationHandler implements InvocationHandler {
    private Object target; // 被代理的对象
  
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在目标方法执行之前可以添加自定义操作
        System.out.println("Before method: " + method.getName());
          
        // 调用目标方法
        Object result = method.invoke(target, args);
          
        // 在目标方法执行之后可以添加自定义操作
        System.out.println("After method: " + method.getName());
          
        return result;
    }
}
  
public class ProxyDemo {
    public static void main(String[] args) {
        // 创建被代理的对象
        Subject realSubject = new RealSubject();
          
        // 创建InvocationHandler对象,并将被代理的对象传递给它的构造器
        InvocationHandler handler = new MyInvocationHandler(realSubject);
          
        // 通过Proxy类为RealSubject类动态创建一个代理对象
        // 第一个参数是类加载器,第二个参数是被代理对象实现的接口列表,第三个参数是InvocationHandler对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
            RealSubject.class.getClassLoader(),
            new Class[] { Subject.class },
            handler
        );
          
        // 通过代理对象调用方法
        proxySubject.request();
    }
}
在这个例子中,RealSubject是被代理的类,它实现了Subject接口。MyInvocationHandler实现了InvocationHandler接口,并在invoke方法中添加了目标方法调用前后的自定义操作。在ProxyDemo的main方法中,我们通过Proxy.newProxyInstance方法为RealSubject动态创建了一个代理对象proxySubject,并通过这个代理对象调用了request方法。你会看到,在调用request方法前后,都打印出了自定义的信息。




原文始发于微信公众号(Java技术前沿):SpringBoot实战:Spring AOP动态代理和静态代理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/299690.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!