java中的动态代理(面试热点)

在Java中,动态代理是一种在运行时动态创建代理类及其对象的技术。与静态代理不同,动态代理的代理类并不是在编译时创建的,而是在运行时根据需要动态生成。这种技术提供了更高的灵活性和可扩展性,因为它允许开发者在运行时根据需要添加或修改代理的行为。

动态代理的实现方式

在Java中,动态代理主要有两种实现方式:基于JDK的动态代理和基于CGLib的动态代理。

1. 基于JDK的动态代理

JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。`Proxy`类提供了创建动态代理类和实例的静态方法,而`InvocationHandler`接口则需要用户实现,以定义代理对象的行为。

JDK动态代理主要适用于实现了接口的类。

示例代码

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

// 定义一个接口
interface Subject {
    void doSomething();
}

// 实现接口的类
class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject.doSomething()");
    }
}

// 实现InvocationHandler接口
class DynamicProxyHandler implements InvocationHandler {
    private Object target; // 真实对象

    public DynamicProxyHandler(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;
    }

    // 获取动态代理的实例
    @SuppressWarnings("unchecked")
    public static <T> T getProxyInstance(T target, Class<T> interfaceType) {
        return (T) Proxy.newProxyInstance(
                interfaceType.getClassLoader(), // 类加载器
                new Class<?>[]{interfaceType}, // 代理类需要实现的接口列表
                new DynamicProxyHandler(target) // 调用处理器
        );
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        // 创建真实对象
        RealSubject realSubject = new RealSubject();

        // 获取动态代理对象
        Subject proxySubject = DynamicProxyHandler.getProxyInstance(realSubject, Subject.class);

        // 通过代理对象调用方法
        proxySubject.doSomething();
    }
}


 

当运行上面的代码时,输出将是:


Before method: doSomething
RealSubject.doSomething()
After method: doSomething


 

在这个例子中,`DynamicProxyHandler`类实现了`InvocationHandler`接口,并在其`invoke`方法中定义了代理的行为。`getProxyInstance`静态方法用于获取动态代理的实例。注意,这个方法的返回类型是泛型,这允许我们创建任何实现了特定接口的代理对象。

2. 基于CGLib的动态代理

CGLib(Code Generation Library)是一个强大的、高性能的、高质量的Code生成类库,它可以在运行时扩展Java类和实现接口。CGLib通过继承的方式动态地创建目标类的子类,从而实现对目标类方法的拦截。

由于CGLib是通过继承的方式实现动态代理的,因此它不仅可以代理实现了接口的类,还可以代理没有实现任何接口的类。但是,由于Java的单继承限制,CGLib动态代理不能代理final类或者final方法。

 示例代码

要使用CGLib,你首先需要将CGLib的jar包添加到你的项目中。以下是一个简单的CGLib动态代理的示例:

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

// 定义一个没有实现接口的类
class RealSubject {
    public void doSomething() {
        System.out.println("RealSubject.doSomething()");
    }
}

// 实现MethodInterceptor接口
class CglibProxyInterceptor 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 CglibDynamicProxyExample {
    public static void main(String[] args) {
        // 创建真实对象
        RealSubject realSubject = new RealSubject();
        
        // 使用CGLib创建动态代理对象
        Enhancer enhancer = Enhancer.create(); // 创建Enhancer实例
        enhancer.setSuperclass(RealSubject.class); // 设置代理类的父类为RealSubject类
        enhancer.setCallback(new CglibProxyInterceptor()); // 设置回调,即我们要实现的逻辑
        RealSubject proxy = (RealSubject) enhancer.create(); // 创建代理对象并返回
        
        // 通过代理对象调用方法
        proxy.doSomething();
    }
}



当运行上面的代码时,输出结果将是:
 

Before method: doSomething
RealSubject.doSomething()
After method: doSomething



在这个例子中,我们使用CGLib库中的`Enhancer`类来创建动态代理。我们首先通过`setSuperclass`方法设置代理类的父类为`RealSubject`。然后通过`setCallback`方法设置回调,即我们实现的逻辑。在这个例子中,我们实现了`CglibProxyInterceptor`来定义代理对象的行为。这个类实现了`MethodInterceptor`接口,它有两个主要的方法:`intercept`和`getProxy』。`intercept`方法负责在目标方法的调用前后添加额外的逻辑。在这个例子中,我们在目标方法执行前后打印出日志信息。最后我们通过调用`create`方法来创建代理对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值