动态代理的理解

前言:本节内容是个人对JDK动态代理过程中实际代理逻辑以及invoke的第一个参数proxy的理解

动态代理

JDK动态代理的理解

参考链接:
1、Java中InvocationHandler接口中第一个参数proxy详解
2、java动态代理和com.sun.proxy.$Proxy0源码解析

注:分块较容易理解
Target接口

public interface Target {
    public String execute();
    Target work(String workName);
}

TargetImpl类实现了Target接口

public final class TargetImpl implements Target {
    @Override
    public String execute() {
        System.out.println("TargetImpl execute");
        return "execute";
    }

    @Override
    public Target work(String workName) {
        System.out.println("工作内容是"+workName);
        return this; // 执行完再返回实例
    }
}

DynamicProxyHandler 类实现了InvocationHandler 接口
注:这里面是真正的代理逻辑

public class DynamicProxyHandler implements InvocationHandler {
    private Target target;

    public DynamicProxyHandler(Target target){
        this.target = target;
    }

    /**
     * 反编译$Proxy0.class文件看源码:
     * this就是创建的目标对象的代理类$Proxy0,它继承了Proxy,实现了目标对象的所有接口
     * this.h就是下面的handler
     * Proxy里面有这么一个变量InvocationHandler h,构造初始化时将handler赋给h
     * m3其实就是通过反射拿到的代理类的对应的方法
     * 源码执行后:this.h.invoke(this, m3, new Object[] { xxx }
     * 就调用下面的invoke(Object proxy, Method method, Object[] args)
     * 总结:
     * jdk代理,实际上是根据目标对象的类加载器,目标对象的所有接口,InvocationHandler里面invoke添加的代理逻辑
     * 重新生成了一个被代理类
     * 补充:
     * 下面的invoke方法里有个参数是proxy,这有什么用呢?
     * 实际上,我们有时候并不是调用一次就结束了, 类似与链式执行方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("dynamic proxy begin...");
/*        System.out.println(proxy.getClass().getName()); // com.sun.proxy.$Proxy0
        System.out.println(target.getClass().getName()); // proxy.TargetImpl*/
        if(method.getName().equals("work")){
            method.invoke(target, args);
            System.out.println("dynamic proxy end: current method work");
            return proxy; // 多次调用
        }
        Object result = method.invoke(target, args); // 注意这里反射执行的对象一定是被代理对象
        System.out.println("dynamic proxy end");
        return result;
    }

    public static void main(String[] args) {
        Target target = new TargetImpl();
        DynamicProxyHandler handler = new DynamicProxyHandler(target);
        // 被代理类的类加载器,被代理类的所有接口,InvocationHandler调用处理逻辑
        // public final class $Proxy0 extends Proxy implements xxx 这个就是新生成的代理类
        Target proxy = (Target) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
        String result = proxy.execute();
        System.out.println();
        Target work = proxy.work("写代码").work("开会").work("下班"); // 链式执行
/*
        dynamic proxy begin...
        TargetImpl execute
        dynamic proxy end

        dynamic proxy begin...
        工作内容是写代码
        dynamic proxy end: current method work
        dynamic proxy begin...
        工作内容是开会
        dynamic proxy end: current method work
        dynamic proxy begin...
        工作内容是下班
        dynamic proxy end: current method work
        */
    }
}

注:
需要根据反编译$Proxy0.class文件结合源码理解invoke执行过程

jdk动态代理本质

运行期间,实际上是根据目标对象的类加载器,目标对象的所有接口,InvocationHandler里面invoke添加的代理逻辑重新生成了一个被代理类,并且实例化得到代理对象
最终,代理对象调用方法,还是通过目标对象调用方法

从中可以看出jdk动态代理的缺陷,因为实现了目标对象的所有接口。
若目标对象未实现接口只是普通类,或要代理的方法不在接口中预先定义而是目标对象的原生方法,则jdk动态代理无法做到。

Cglib动态代理

Target 接口

public interface Target {
    public String execute();
    //Target work(String workName);
}

TargetDomain 实体类

public class TargetDomain {
    public String execute(){
        String msg = "--------test------------";
        System.out.println(msg);
        return msg;
    }
}

TargetImpl 实现Target 接口

public  class TargetImpl implements Target {
    @Override
    public String execute() {
        System.out.println("TargetImpl execute");
        return "execute";
    }

    public Target work(String workName) {
        System.out.println("工作内容是"+workName);
        return this; // 执行完再返回实例
    }
}

关键在于:实现一个MethodInterceptor接口,重写intercept方法,添加代理逻辑

public class CglibMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib proxy begin...");
        Object result = methodProxy.invokeSuper(obj, args);
        System.out.println("cglib proxy end");
        return result;
    }



    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TargetImpl.class.getClassLoader());
        // 设置需要代理的类
        enhancer.setSuperclass(TargetImpl.class);
        // 设置一个callback对原始类方法做增强
        enhancer.setCallback(new CglibMethodInterceptor());
        // 设置方法过滤器,分别执行callback
        //enhancer.setCallbackFilter();
        // 创建代理对象
        //TargetDomain proxy = (TargetDomain) enhancer.create();
        TargetImpl proxy = (TargetImpl) enhancer.create();
        String result = proxy.execute();
        System.out.println(result);
        /*
        cglib proxy begin...
        --------test------------
        cglib proxy end
        */
    }
}

CglibProxyFactory 包装类,传入目标对象的类对象,生成代理对象

public class CglibProxyFactory {
    public static Object getProxy(Class<?> clazz) {
        // 创建动态代理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(clazz);
        // 设置方法拦截器
        enhancer.setCallback(new CglibMethodInterceptor());
        // 创建代理类
        return enhancer.create();
    }
}

CglibProxy 测试类

public class CglibProxy {
    public static void main(String[] args) {
        TargetImpl proxy1 = (TargetImpl) CglibProxyFactory.getProxy(TargetImpl.class);
        proxy1.execute(); // 接口
        System.out.println();
        proxy1.work("吃饭");
        System.out.println();
        TargetDomain proxy2 = (TargetDomain) CglibProxyFactory.getProxy(TargetDomain.class);
        proxy2.execute();
    }
    /*
    cglib proxy begin...
    TargetImpl execute
    cglib proxy end

    cglib proxy begin...
    工作内容是吃饭
    cglib proxy end

    cglib proxy begin...
            --------test------------
    cglib proxy end
    */
}

总结:
Cglib动态代理是通过继承目标类生成子类对象,即代理对象
可以看出:
1、可以代理未实现接口的目标对象,也可以代理实现接口的目标对象,拦截目标对象的原生方法或实现的接口中的方法
2、JDK 动态代理只能只能代理实现了接口的类,而 CGLIB 可以代理未实现任何接口的类
3、感觉CGLIB也能把JDK 动态代理做的事情做完
特别注意:
1、Cglib动态代理的目标对象不能是final修饰,因为需要继承生成子类
2、JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
3、动态代理更灵活

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值