简单的动态代理归纳------基于接口和子类
一:动态代理概述
- 特点: 字节码随用随创建,在不修改源码的情况下,对源码进行增强
- 分类: 基于接口 和基于子类
二:基于接口的动态代理
- 涉及的类:Proxy(JDK官方提供)
- 如何创建代理对象: 使用Proxy中的newProxyInstance(被代理对象的类加载器,被代理对象的实现的接口,实现增强方法)
- 创建代理对象的要求: 被代理类至少要实现一个接口,如果没有则不能使用
- newProxyInstance方法的参数:
-
ClassLoader:类加载器
- 用于加载代理对象字节码的,和被代理对象使用相同的类加载器
代理Producer,就用Producer.getClass().getClassLoad()--------固定写法
- 用于加载代理对象字节码的,和被代理对象使用相同的类加载器
- Interfaces:Class<?>{} 被代理对象的实现的接口
- 用于让代理对象和被代理对象有相同方法:实现同一个接口
代理Producer: 就写: Producer.getClass().getInterfaces()-------固定写法
- 用于让代理对象和被代理对象有相同方法:实现同一个接口
- InvocationHandler: 实现增强方法
- 提供增强代码,如何代理
一般写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的
此接口的实现类都是谁用谁写
- 提供增强代码,如何代理
-
三.代码演示
创建一个基本JavaBean: Producer 及其实现的接口IProducer
接口IProducer
/** * 对生产厂家要求的接口 */ public interface IProducer { void saleProduct(float money); void afterService(float money); }
基本JavaBean: Producer
/** * 生产者 */ public class Producer implements IProducer{ /** * 销售 * @param money */ public void saleProduct(float money){ System.out.println("销售产品,并拿到钱" + money); } /** * 售后 * @param money */ public void afterService(float money){ System.out.println("提供售后,并拿到钱" + money); } }
再创建一个客户端测试类: Client
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 模拟消费者 */ public class Client { public static void main(String[] args) { final Producer producer = new Producer(); /** * 动态代理特点,字节码随用随创建,在不修改源码的情况下,对源码进行增强 * 分类: * 基于子类 * 基于接口: * 涉及的类:Proxy * 提供者:JDK官方 * 如何创建代理对象: * 使用Proxy中的newProxyInstance(类加载器,实现的接口,增强方法) * 创建代理对象的要求 * 被代理类至少要实现一个接口,如果没有则不能使用 * newProxyInstance参数: * ClassLoader:类加载器 * //用于加载代理对象字节码的,和被代理对象使用相同的类加载器 * //代理Producer,就用其对象producer.getClass().getClassLoad() 固定写法 * Interfaces:Class<?>{} * //用于让代理对象和被代理对象有相同方法:实现同一个接口 * //代理Producer: 就写: producer.getClass().getInterfaces(). 固定写法 * InvocationHandler:h //处理器 * //提供增强代码,如何代理 * //一般写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的 * //此接口的实现类都是谁用谁写 * */ IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { /** * 作用:执行被代理对象的任何接口方法都会经过该方法 * 方法参数含义: * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需的参数 * @return 被代理对象返回值 * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //提供增强的代码 //代理收取拿20% //1.获取方法执行的参数 Float money = (Float) args[0]; if("saleProduct".equals(method.getName())){ method.invoke(producer, money*0.8f); } return null; } });
//很重要的一点: 实际调用方法的是我们创建的代理类,这个一定要注意. proxyProducer.saleProduct(10000); } }
打印结果:
销售产品,并拿到钱8000.0
Process finished with exit code 0
以上为对基于接口的动态代理的简单演示,及其中涉及的参数的解释
四.基于子类的动态代理
- 涉及的类:Enhancer(第三方cglib库)
- 如何创建代理对象: 使用Enhancer中的create(被代理对象的字节码文件,增强方法)
- 创建代理对象的要求: 被代理类不能是最终类
- create方法的参数:
-
Class type:字节码
- 用于指定被代理对象的字节码
代理producer,就用其对象producer.getClass()--------固定写法
- 用于指定被代理对象的字节码
- Callback:用于提供增强的代码
- 它是让我们写如何代理,我们一般都是写一些该接口的实现类,
通常情况下都是匿名内部类,但不是绝对的
用的该接口的子接口实现类:MethodInterceptor-------固定写法
- 它是让我们写如何代理,我们一般都是写一些该接口的实现类,
-
- 导入第三方jar包: net.sf.cglib
五.代码演示
和基于接口使用同一个JavaBean: Producer (删除掉实现接口)
模拟客户的测试类
import cn.itheima.proxy.Producer; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * 模拟消费者 */ public class Client { public static void main(String[] args) { final Producer producer = new Producer(); /** * 动态代理特点,字节码随用随创建,在不修改源码的情况下,对源码进行增强 * 分类: * 基于接口 * 基于子类: * 涉及的类:Enhancer * 提供者:第三方cglib库 * 如何创建代理对象: * 使用Enhancer中的create() * 创建代理对象的要求 * 被代理类不能是最终类 * 什么叫最终类: * create参数: * Class type:字节码 * 用于指定被代理对象的字节码 * 代理producer,就用其对象producer.getClass() 固定写法 * Callback:用于提供增强的代码 * 它是让我们写如何代理,我们一般都是写一些该接口的实现类, * 通常情况下都是匿名内部类,但不是绝对的 * 用的该接口的子接口实现类:MethodInterceptor */ Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() { /** * 执行被代理对象的任何方法都会经过该方法 * @param proxy * @param method * @param args * 以上三个参数和基于接口的动态代理中invoke方法参数是一样的 * @param methodProxy :当前执行方法的代理对象 * @return * @throws Throwable */ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //提供增强的代码 //代理收取拿20% //1.获取方法执行的参数 Float money = (Float) args[0]; if ("saleProduct".equals(method.getName())) { method.invoke(producer, money * 0.8f); return null; } return null; } }); cglibProducer.saleProduct(10000); } }
打印结果
销售产品,并拿到钱8000.0
Process finished with exit code 0
六.总结
posted on 2018-09-06 11:23 Yiran_shampin 阅读(156) 评论(0) 收藏 举报