likes
comments
collection
share

java动态代理

作者站长头像
站长
· 阅读数 1

动态代理是指在程序运行过程中动态地创建代理类和对象的技术。通过动态代理,我们可以在不修改源代码的情况下,在方法执行前后加入一些附加操作,比如日志记录、性能统计、事务管理等。

在 Java 中,动态代理主要有两种实现方式:

1. 基于接口的动态代理(JDK 动态代理):使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来创建代理对象。被代理的类必须实现一个或多个接口。

2. 基于继承的动态代理(CGLIB 动态代理):使用 CGLIB 库来创建代理对象,无需被代理的类实现接口。

动态代理常用于 AOP(面向切面编程)等方面,它可以帮助我们将与核心业务逻辑相关的横切关注点(如日志记录、事务管理等)与业务逻辑本身分离。这样可以提高代码的模块化程度,使得代码更易于维护和升级。

动态代理是一种在运行时动态生成代理对象的技术,它允许在不修改原始类的情况下,通过代理对象来间接访问原始类的方法。动态代理常用于 AOP(面向切面编程)和基于接口的代理。

基于接口的动态代理(JDK 动态代理)

1. 基于接口的动态代理(JDK 动态代理):基于 Java 的反射机制,利用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现动态代理。JDK 动态代理要求被代理的类必须实现一个或多个接口。

下面是一个简单的示例代码,演示如何使用 JDK 动态代理:

interface Calculator {  
    int add(int a, int b);  
}  
  
class CalculatorImpl implements Calculator {  
    public int add(int a, int b) {  
        return a + b;  
    }  
}  
  
class LoggingInvocationHandler implements InvocationHandler {  
    private Object target;  
  
    public LoggingInvocationHandler(Object target) {  
        this.target = target;  
    }  
  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        System.out.println("Before invoking method: " + method.getName());  
        Object result = method.invoke(target, args);  
        System.out.println("After invoking method: " + method.getName());  
        return result;  
    }  
}  
  
public class DynamicProxyExample {  
    public static void main(String[] args) {  
        Calculator calculator = new CalculatorImpl();  
        Calculator proxy = (Calculator) Proxy.newProxyInstance(  
                calculator.getClass().getClassLoader(),  
                calculator.getClass().getInterfaces(),  
                new LoggingInvocationHandler(calculator));  
  
        int result = proxy.add(23);  // 这里实际上会调用 LoggingInvocationHandler 中的 invoke 方法  
        System.out.println("Result: " + result);  
    }  
}  

CGLIB

CGLIB(Code Generation Library)是一个强大的基于字节码的代码生成库,它可以在运行时动态地生成新的 class。CGLIB 动态代理是指使用 CGLIB 库来生成代理类,并通过代理类来实现对目标类的代理。

与基于接口的动态代理不同,CGLIB 动态代理可以代理没有实现任何接口的类。它通过生成目标类的子类,并在子类中对目标类的方法进行拦截和增强实现代理功能。

在 CGLIB 动态代理中,代理类的生成过程主要包括以下几个步骤:

1. 创建 Enhancer 对象:使用 CGLIB 提供的 Enhancer 类创建一个代理类生成器对象。

2. 设置目标类(被代理类):将目标类设置为 Enhancer 对象的父类,以便生成的代理类成为目标类的子类。

3. 设置回调函数(Interceptor):使用 Enhancer 对象的 setCallback 方法设置方法拦截器,也就是在代理对象调用方法时的增强逻辑。

4. 创建代理对象:通过 Enhancer 对象的 create 方法创建代理对象,并将代理对象强制转换为目标类类型。

CGLIB 动态代理的实现原理相对复杂,但它具有很强的灵活性和扩展性,可以代理没有实现接口的类,从而能够对更多类型的类进行代理。它在 Spring 等框架中被广泛应用,用于实现 AOP 功能、对目标类进行增强等方面。

使用 CGLIB 动态代理需要引入 CGLIB 库,并按照以下步骤进行操作:

1. 引入 CGLIB 库:在 Maven 项目中,在 pom.xml 文件中加入以下依赖:

<dependency>  
    <groupId>cglib</groupId>  
    <artifactId>cglib</artifactId>  
    <version>3.3.0</version>    
</dependency>  

或者在 Gradle 项目中,在 build.gradle 文件中加入以下依赖:

dependencies {  
    implementation 'cglib:cglib:3.3.0'  // 替换为最新版本  
}  

2. 创建目标类:创建一个普通的 Java 类作为被代理的目标类。

3. 创建拦截器(Interceptor)类:编写一个类来实现对目标类方法的拦截和增强逻辑。

4. 使用 Enhancer 生成代理对象:使用 CGLIB 的 Enhancer 类来生成代理类,并创建代理对象。

下面是一个简单的示例,演示了如何使用 CGLIB 动态代理:

import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
// 目标类  
class TargetClass {  
    public void doSomething() {  
        System.out.println("TargetClass: Doing something...");  
    }  
}  
  
// 拦截器类  
class MyInterceptor implements MethodInterceptor {  
    @Override  
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
        System.out.println("Before method " + method.getName());  
        Object result = proxy.invokeSuper(obj, args); // 调用目标类的方法  
        System.out.println("After method " + method.getName());  
        return result;  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(TargetClass.class);  
        enhancer.setCallback(new MyInterceptor());  
  
        TargetClass proxy = (TargetClass) enhancer.create();  
        proxy.doSomething(); // 调用代理对象的方法  
    }  
}