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:清朝云网络工作室

阅读剩余
THE END