Java 彻底理解两种动态代理
共计 2523 个字符,预计需要花费 7 分钟才能阅读完成。
在 java 中,有两种常见的动态代理实现方式,即基于接口的动态代理(JDK 动态代理)和基于类的动态代理(CGLIB 动态代理),下面就对这两种代理进行解释和举例。
1. JDK动态代理
这种动态代理实现方式是基于接口的,使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来创建代理对象。代理对象实现了目标接口,并将方法调用委托给提供的 InvocationHandler 实现类来处理。这种方式要求目标类实现接口,因此只能代理接口定义的方法。
这里最重要的就是需要实现 InvocationHandler 接口,在 invoke 方法中添加增强代码,而目标代码的执行就一行代码 res = method.invoke(target,args);
。
代码如下:
动态代理类:MyInvocationHandler.java
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler() {
}
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 通过代理对象执行方法时候,会调用执行这个invoke方法
Object res = null;
System.out.println("目标方法执行时间:" + new Date());
// 执行目标类方法,通过method类实现
res = method.invoke(target,args); //实现SomeServiceImpl.doOthers() doSome()方法
System.out.println("提交事务....");
//目标方法执行结果
return res;
}
}
接口类:SomeService.java
public interface SomeService {
public void doSome();
}
接口实现类:SomeServiceImpl.java
public class SomeServiceImpl implements SomeService {
@Override
public void doSome() {
System.out.println("执行doSome方法");
}
}
测试类:Test.java
public class Test {
/**
* 测试动态代理
*/
public static void main(String[] args) {
// 创建目标类
SomeService target = new SomeServiceImpl();
// 创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(target);
// 使用Proxy创建代理
SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),handler);
proxy.doSome();
}
}
2. CGLIB动态代理
这种动态代理实现方式使用第三方库(如 CGLIB)来生成代理类。CGLIB(Code Generation Library)通过继承目标类创建代理对象,代理对象可以直接调用目标类的方法,并在方法调用前后执行自定义的逻辑。相比于 JDK 动态代理,CGLIB 动态代理可以代理具体类而不仅限于接口。
具体类:SomeService.java
public class SomeService {
public void doSome() {
System.out.println("执行doSome方法");
}
}
拦截器类:SomeServiceInterceptor.java
public class SomeServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("目标方法执行时间:" + new Date());
Object result = proxy.invokeSuper(obj, args);
System.out.println("提交事务....");
return result;
}
}
测试类:Test.java
public class Test {
/**
* 测试动态代理
*/
public static void main(String[] args) {
// CGLIB 动态代理的核心类
Enhancer enhancer = new Enhancer();
// 设置需要动态代理的类,代理类将继承此类
enhancer.setSuperclass(SomeService.class);
// 设置拦截器
enhancer.setCallback(new SomeServiceInterceptor());
// 创建代理类
SomeService proxy = (SomeService) enhancer.create();
proxy.doSome();
}
}
如果需要判断类是由哪种动态代理生成,打印类名即可判断。
在 JDK 动态代理中,生成的代理类名通常遵循以下模式:$ProxyN,其中 N 是一个递增的数字。例如,$Proxy0、$Proxy1 等。
在 CGLIB 动态代理中,生成的代理类名通常遵循以下模式:SomeService$$EnhancerByCGLIB$$RandomNumber,其中 SomeService 是原始类的名字,RandomNumber 是一个随机生成的数字。
提醒:本文发布于498天前,文中所关联的信息可能已发生改变,请知悉!
Tips:清朝云网络工作室