jdk动态代理和cglib动态代理

代理设计模式:
定义:对其他对象提供一种代理以控制对这个对象的访问。

特征:代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

按照代理的创建时期,代理类可以分为两种:

1. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
2. 动态代理:在程序运行时,运用反射机制动态创建而成。 

其中动态代理也可分为两种:

	1.jdk动态代理
	2.cglib动态代理

先讲一下静态代理:
比如有一个接口Actor

public interface Actor {
	//表演
    void act();
    //跳舞
    void dance();
}

艺人王宝强实现了这个接口

public class WangBaoQiang implements Actor {
    @Override
    public void act() {
        System.out.println("宝强表演");
    }
    @Override
    public void dance() {
        System.out.println("宝强跳舞");
    }
}

创建一个静态代理对象负责照顾王宝强的行程安排staticProxy

public class StaticProxy implements Actor {
    private Actor actor = new WangBaoQiang();
    @Override
    public void act() {
        System.out.println("确认钱到位了,让宝强表演");
        //调用原有功能的原有方法
        actor.act();
    }
    @Override
    public void dance() {
        System.out.println("确认钱到位了,让宝强跳舞");
        actor.dance();
    }
    public static void main(String[] args) {
        StaticProxy staticProxy = new StaticProxy();
        staticProxy.act();
        staticProxy.dance();
    }
}

以上就是静态代理,静态代理对象需要自己创建,

jdk动态代理

public class JdkProxy {
    public static void main(String[] args) {
        //1.创建被代理对象
        Actor actor = new WangBaoQiang();
        //2.创建王宝强的代理对象proxyActor--经纪人
        /**
         * loader – the class loader to define the proxy class 加载此对象(Actor.class)所表示的类或接口的类加载器。
         * interfaces – the list of interfaces for the proxy class to implement 代理类实现的接口列表
         * h – the invocation handler to dispatch method invocations to
         */
        //定义代理类加载器
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        //getClass:返回此对象运行的类(.class),getInterfaces:返回此类实现的接口列表(.class)
        Class<?>[] interfaces = actor.getClass().getInterfaces();
        Actor proxyActor = (Actor) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            /**
             * @param proxy 方法所调用的代理实例
             * @param method 对应于在代理实例上调用的接口方法的方法实例。
             * @args 一个对象数组,包含在代理实例的方法调用中传递的参数的值,如果接口方法不接受参数,则为null。原始类型的参数被包装在适当的原始包装类的实例中
             * @return 方法执行的返回值
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("经纪人确认钱到位了");
                //保证原有方法的功能,即调用原有对象的原有方法
                Object obj = method.invoke(actor, args);
                System.out.println("表演结束,经纪人帮助王宝强安排住宿");
                return obj;
            }
        });
        //3.调用代理对象执行方法(保证具体的业务功能由被代理对象自己完成,而事务功能由代理对象来完成.)
        proxyActor.act();
        System.out.println("=================");
        proxyActor.dance();
    }
}

debug执行结果:

Connected to the target VM, address: '127.0.0.1:14151', transport: 'socket'
经纪人确认钱到位了
宝强表演
表演结束,经纪人帮助王宝强安排住宿
=================
经纪人确认钱到位了
宝强跳舞
表演结束,经纪人帮助王宝强安排住宿
Disconnected from the target VM, address: '127.0.0.1:14151', transport: 'socket'

Process finished with exit code 0

查看jvm虚拟机生成的动态代理类源码:
在图片所指向的位置输入:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true,运行代码即可生成代理类源码

在这里插入图片描述
代理类源码

public final class $Proxy0 extends Proxy implements Actor {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void dance() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void act() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.itheima.poxy.jdk.Actor").getMethod("dance");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.itheima.poxy.jdk.Actor").getMethod("act");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

由代码可知,该代理类继承了Proxy动态代理类并实现了Actor接口
Proxy类:
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
可查看API中 java.lang.reflect.Proxy
在这里插入图片描述
第一步
静态代码块首先获取方法对象并赋值给私有静态成员变量.
在这里插入图片描述
在这里插入图片描述
第二步
通过InvocationHandler h调用invoke方法,并传递三个参数,代理对象,方法对象(m1,m4,m2…),方法参数.

    protected InvocationHandler h;
    private Proxy() {
    }

而查看InvocationHandler发觉它就一个方法

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

在这里插入图片描述
而这个InvocationHandler对象是我们在创建代理类对象创建的匿名内部类对象.
在这里插入图片描述
所以,Proxy.newProxyInstance传递三个参数(类加载器,方法对象,h对象)创建代理对象,当我们通过代理对象调用方法时,本质就是调用super.h.invoke(this, m1, new Object[]{var1}),而这个h变量就是我们传递进去的匿名内部类对象赋值的,所以有趣的是,当我们用代理对象调用方法,比如jdkProxy.dance(),会去调用invoke方法,而invoke方法的第一个参数是代理对象本身,如果我们再invoke方法内部继续调用dance(),就会发生递归现象
在这里插入图片描述
在这里插入图片描述
由于jdk的动态代理方式创建代理对象必须使用接口,在企业开发中有时没有接口,需要对某个实现类进行代理,那么此时我们就不能再使用jdk动态代理而选择cglib动态代理.
cglib动态代理:通过对现有类的继承,这个继承类是动态创建的

需要被代理的类

public class WangBaoQiang {
    public void act() {
        System.out.println("表演");
    }
}

使用cglib动态生成代理对象.(使用前记得导入cglib依赖)

public class Cglib {
    public static void main(String[] args) {
        WangBaoQiang wangBaoQiang = new WangBaoQiang();
        /**
         * 参数1:被代理对象的实现类
         * 参数2:处理器,和jdk的动态代理中的invocationHandler的作用一样
         */
        WangBaoQiang o = (WangBaoQiang) Enhancer.create(WangBaoQiang.class, new MethodInterceptor() {
            //作用和jdk动态代理中invoke的作用一样

            /**
             *
             * @param o 代理对象本身 没卵用
             * @param method 代理对象将要代理的方法
             * @param objects 方法中的参数
             * @param methodProxy 代理后的方法 没卵用
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //方法增强
                System.out.println("经纪人确认钱到账,安排宝强表演");
                //保证原有方法的功能,即调用原有对象的原有方法
                Object obj = method.invoke(wangBaoQiang, objects);
                return obj;
            }
        });
        //代理对象调用方法
        o.act();
    }
}

执行结果:

E:\develop\Java\jdk-8\bin\java.exe "-javaagent:E:\develop\JetBrains\IntelliJ IDEA 2019.1.4\lib\idea_rt.jar=14095:E:\develop\JetBrains\IntelliJ IDEA 2019.1.4\bin" -Dfile.encoding=UTF-8 -classpa
经纪人确认钱到账,安排宝强表演
表演

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值