理解jdk和cglib动态代理

本文详细介绍了JDK和CGlib动态代理的实现原理。JDK动态代理基于接口,通过Proxy.newProxyInstance创建代理对象,利用InvocationHandler进行方法拦截;而CGlib动态代理则无需实现接口,通过继承目标类生成子类实现代理,使用MethodInterceptor接口进行方法拦截。文中还给出了具体的代码示例和测试输出,展示了如何在实际操作中应用这两种动态代理技术。

理解jdk和cglib动态代理

jdk动态代理:

jdk动态代理实现前提:必须实现接口。

核心其实是借助【Proxy.newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandler h)】方法,去创建的动态代理对象

首先简单定义一个fuwu接口, 里面存在四个接口方法。便于理解有无返回值,有无参数。

public interface Fuwu {

    /**
     *  void 类型
     */
    void do1();

    /**
     *  int 类型
     */
    int do2();

    /**
     * 有参方法
     */
    void do3(int i);

    /**
     * 有参方法
     */
    int do4(int j);
}

其次, 我们需要定义该接口的实现类,也就是我们的目标类(即你真正需要代理的类)。

public class Target implements Fuwu {

    @Override
    public void do1() {
        System.out.println("do1 method 无返回值, 无参数");
    }

    @Override
    public int do2() {
        System.out.println("do2 method 有返回值, 无参数");
        return 0;
    }

    @Override
    public void do3(int i) {
        System.out.println("do3 method 无返回值, 有参数");
    }

    @Override
    public int do4(int j) {
        System.out.println("do4 method 有返回值, 有参数");
        return j;
    }
}

那么代理类是如何运行的?

我们通过反编译可以知道在运行过程中动态生成了代理类Proxy0;为了便于理解,我们先自定义实现Proxy0; 为了便于理解,我们先自定义实现Proxy0;为了便于理解,我们先自定义实现Proxy0;

核心就在于InvocationHandler 接口。InvocationHandler就是代理实例创建时调用的处理程序, 每个实例交由invoke方法来进行代理。

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
一: 自定义代理类$Proxy0(具体见注释):
public class $Proxy0 extends Proxy implements Fuwu {

	// 调用父类构造来初始化InvocationHandler
    public $Proxy0(InvocationHandler h) {
        super(h);
    }
	// 对应需要代理的方法
    static Method do1;
    static Method do2;
    static Method do3;
    static Method do4;
    
	// 通过反射来初始化代理方法, 静态代码块中的异常记得要抛出
    static {
        try {
            do1 = Target.class.getMethod("do1");
            do2 = Target.class.getMethod("do2");
            do3 = Target.class.getMethod("do3", int.class);
            do4 = Target.class.getMethod("do4", int.class);
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }

    }
    
    @Override
    public void do1() {
        try {
        	// 真正代理执行do1方法
            h.invoke(this, do1, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }

    }

    @Override
    public int do2() {
        try {
        	// 真正代理执行do2方法
            return (int) h.invoke(this, do2, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }

    }

    @Override
    public void do3(int i) {
        try {
        	// 真正代理执行do3方法
            h.invoke(this, do3, new Object[]{i});
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public int do4(int j) {
        try {
        	// 真正代理执行do4方法
            return (int) h.invoke(this, do4, new Object[]{j});
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

测试: (输出放在最后)

        // 在真正调用时传入InvocationHandler,可以降低代码耦合
        Fuwu proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            	// 对应的增强逻辑
                System.out.println("before...可增强逻辑");
                // 执行代理 并返回
                return method.invoke(new Target(), args);
            }
        });
        // 代理执行:
        proxy.do1();
        System.out.println(proxy.do2());
        proxy.do3(10);
        System.out.println(proxy.do4(20));
二: 调用核心方法newProxyInstance来创建代理类

这里就不用自定义实现了,因为对应实现其实就是newProxyInstance方法调用逻辑,并且该方法更完善。

实现InvocationHandler接口:

public class MyH implements InvocationHandler {
	
	// 目标代理类
    private Fuwu target;

    public MyH(Fuwu target) {
        this.target = target;
    }

	// 代理执行 同上
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("增强逻辑 实现InvocationHandler");
        return method.invoke(target, args);
    }
}

测试:

		Fuwu t1 = new Target();
        Fuwu newProxyInstance = (Fuwu) Proxy.newProxyInstance(Target.class.getClassLoader(),
                Target.class.getInterfaces(), new MyH(t1));
        newProxyInstance.do1();
        System.out.println(newProxyInstance.do2());
        newProxyInstance.do3(10);
        System.out.println(newProxyInstance.do4(10));
输出:
增强逻辑 实现InvocationHandler
do1 method 无返回值, 无参数
增强逻辑 实现InvocationHandler
do2 method 有返回值, 无参数
0
增强逻辑 实现InvocationHandler
do3 method 无返回值, 有参数
增强逻辑 实现InvocationHandler
do4 method 有返回值, 有参数
10
-------------------------------------
before...可增强逻辑
do1 method 无返回值, 无参数
before...可增强逻辑
do2 method 有返回值, 无参数
0
before...可增强逻辑
do3 method 无返回值, 有参数
before...可增强逻辑
do4 method 有返回值, 有参数
20

cglib动态代理

cglib动态代理就没有jdk动态代理需要实现接口的局限,它本质是通过继承目标代理类来实现动态代理。

具体实现原理:

其实看上去和jdk动态代理差不多,只不过换了个拦截器一样,需要用到MethodInterceptor。看懂了上面其实这里很好懂。

其中定义了一个intercept接口方法,其中有一个MethodProxy(生成的类将此对象传递给

在调用被拦截的方法时注册MethodInterceptor对象。它可以用于调用原始方法,或对不同的方法调用相同的方法) 感兴趣可以看看源码,用来实现增强式的方法。

public interface MethodInterceptor extends Callback {
    Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable;
}

通过继承来实现代理:

public class Proxy extends Targt{

    private MethodInterceptor methodInterceptor;

    public Proxy() {
    }

    public Proxy(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    static Method do1;
    static Method do2;
    static Method do3;
    static Method do4;

    static {
        try {
            do1 = Targt.class.getMethod("do1");
            do2 = Targt.class.getMethod("do2");
            do3 = Targt.class.getMethod("do3", int.class);
            do4 = Targt.class.getMethod("do4", int.class);
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }
    @Override
    public void do1() {
        try {
            methodInterceptor.intercept(this, do1, new Object[0], null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }

    }

    @Override
    public int do2() {
        try {
            return (int) methodInterceptor.intercept(this, do2, new Object[0], null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }

    }

    @Override
    public void do3(int i) {
        try {
            methodInterceptor.intercept(this, do3, new Object[]{i}, null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public int do4(int j) {
        try {
            return (int) methodInterceptor.intercept(this, do4, new Object[]{j}, null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

测试:

@Test
    public void testcglib() {
        Proxy proxy = new Proxy();
        Targt targt = new Targt();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("增强逻辑...");

                return method.invoke(targt, objects);
            }
        });
        proxy.do1();
        System.out.println(proxy.do2());
        proxy.do3(2);
        System.out.println(proxy.do4(2));
    }
输出:
增强逻辑...
do1 method 无返回值, 无参数
增强逻辑...
do2 method 有返回值, 无参数
0
增强逻辑...
do3 method 无返回值, 有参数
增强逻辑...
do4 method 有返回值, 有参数
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值