Bootstrap

静态代理和动态代理

更多Java基础相关知识点详见个人主页【Java基础相关】专栏

静态代理和动态代理

静态代理

定义

  • 静态代理是一种在【编译时】确定代理类的代理方式。它通过手动创建代理类,该代理类实现了与被代理类相同的接口,并在方法中调用实际的被代理对象来完成相应的工作

工作流程

  1. 定义一个接口,该接口包含了要被代理对象的方法
  2. 创建一个代理类,实现上述接口,并在方法中调用实际的被代理对象来执行相应的操作
  3. 创建一个被代理对象的实例
  4. 创建代理对象的实例,将被代理对象的实例传递给代理对象
  5. 调用代理对象的方法,代理对象将方法调用传递给被代理对象进行处理

优缺点

  • 优点:简单易懂
  • 缺点:手动创建代理类,如果被代理类的方法很多,会导致代码冗余

动态代理

定义

  • 动态代理是一种在【运行时】通过反射机制动态生成代理对象,并在代理对象上进行方法调用的编程技术,主要用于在不修改原有代码的基础上,增加或改变某些功能的执行流程
  • 动态代理广泛应用于AOP(面向切面编程),RPC(远程过程调用)、事务管理等领域
  • 在Java中,主要有JDK动态代理和CGLIB动态代理两种实现方式

JDK动态代理

原理

  • JDK动态代理是基于接口的代理技术
  • 它使用 java.lang.reflect.proxy 类和 java.lang.reflect.InvocationHandler 接口来创建代理对象。当你调用代理对象的任何方法时,调用会被转发到 InvocationHandlerinvoke 方法。你可以在这个 invoke 方法中定义拦载逻辑,比如前置处理,后置处理等
  • 为了使用 JDK动态代理,你的类必须实现一个或多个接口。JDK动态代理的局限性在于,它只能代理接口方法,如果你有一个类并希望代理其非接口方法,则不能使用 JDK动态代理

工作流程

  1. 定义一个接口及其实现类
  2. 创建一个实现了 InvocationHandler 接口的类,在该类的 invoke 方法中定义代理逻辑
  3. 通过 Proxy.newProxyInstance 方法动态创建接口的代理对象

优缺点

  • 优点:原生支持,无需引入额外依赖
  • 缺点:只能代理接口,如果一个类没有实现任何接口,则不能使用JDK动态代理

代码实现

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 目标接口
interface MyService {
   void doSomething();
}

// 目标对象的实现
class MyServiceImpl implements MyService {
   @Override
   public void doSomething() {
       System.out.println("Doing something...");
   }
}

// 动态代理处理器
class MyInvocationHandler implements InvocationHandler {
   private final 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 call");
       Object result = method.invoke(target, args);
       System.out.println("After method call");
       return result;
   }
}

// 使用动态代理
public class Main {
   public static void main(String[] args) {
       MyService target = new MyServiceImpl();
       MyService proxy = (MyService) Proxy.newProxyInstance(
           target.getClass().getClassLoader(),
           target.getClass().getInterfaces(),
           new MyInvocationHandler(target)
       );

       proxy.doSomething();
   }
}

CGLIB动态代理

  • CGLlB(Code Generation library)是一个强大的、高性能、高质量的代码生成库,它可以在运行时扩展 Java 类和实现,Java 接口
  • 不同于JDK动态代理,CGLIB 不需要接口,它是通过继承方式实现代理的
  • CGLB 底层通过使用一个小而快的字节码处理框架 ASM ,来转换字节码并生成新的类。不仅可以代理普通类的方法,还能代理那些没有接口的类的方法

工作流程

  1. 创建一个需要被代理的类
  2. 创建一个继承 MethodInterceptor 的代理类,在 intercept 方法中定义代理逻辑
  3. 使用Enhancer 类创建被代理类的子类,并设置回调

优缺点

  • 优点:无需接口实现,在大量调用的场景下,其生成的代理对象在调用时性能比JDK动态代理高对
  • 缺点:final 方法无效,需添加额外的依赖

代码实现

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 目标类
class MyService {
   public void doSomething() {
       System.out.println("Doing something...");
   }
}

// CGLIB 代理处理器
class MyInterceptor implements MethodInterceptor {
   @Override
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
       System.out.println("Before method call");
       Object result = proxy.invokeSuper(obj, args);
       System.out.println("After method call");
       return result;
   }
}

// 使用 CGLIB 动态代理
public class Main {
   public static void main(String[] args) {
       Enhancer enhancer = new Enhancer();
       enhancer.setSuperclass(MyService.class);
       enhancer.setCallback(new MyInterceptor());

       MyService proxy = (MyService) enhancer.create();
       proxy.doSomething();
   }
}

静态代理和动态代理的区别

具体区别

  • 静态代理:由程序员创建或者是由特定工具创建,在代码编译时就确定了被代理的类是一个静态代理。静态代理通常只代理一个类
  • 动态代理:在代码运行期间,运用反射机制动态创建生成。动态代理代理的是一个接口下的多个实现类
;