动态代理的总结
1.动态代理分类
我们设计一个应用的场景:
以前的导演剧组找演员的时候,直接到家里找这个演员谈价格就可以让他演戏,但是随着时代的发展,出现了经济公司,签约演员。 现在让演员演出就要直接找经济公司,不能找演员。
1.1基于接口的动态代理
// 创建一个演员的角色 public class Actor implements IActor { ? /** * 基本表演 * @param money */ @Override public void basicAct(Float money){ System.out.println("拿到钱,开始基本的表演:"+money); } ? /** * 危险的表演 * @param money */ @Override public void dangerAct(Float money){ System.out.println("拿到钱,开始危险的表演:"+money); } } ? ? ? // 模拟经济公司的标准 public interface IActor { /** * 基本表演 * @param money */ public void basicAct(Float money); /** * 危险的表演 * @param money */ public void dangerAct(Float money); }
?
然后我们模拟一个剧组,通过经济公司来找演员,但是经济公司也有自己的标准,就是参数money
public class Client { ? public static void main(String[] args) { //早期:直接去家里找 Actor actor = new Actor(); ? //通过经纪公司来找演员 ? IActor proxyActor = (IActor)Proxy.newProxyInstance(actor.getClass().getClassLoader(), actor.getClass().getInterfaces(), new InvocationHandler() { /** * 此处提供增强的代码 * 执行被代理对象的任何方法,都会经过该方法。 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前方法所需的参数 * @return 和被代理对象的方法具有相同的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object rtValue = null; //1.取出当前方法的参数 Float money= (Float) args[0]; //2.判断方法是什么 if("basicAct".equals(method.getName())){ //基本演出:抽取20% 要求一天5000块以上才接 if(money > 5000f){ rtValue = method.invoke(actor,money*0.8f); } } if("dangerAct".equals(method.getName())){ //高危演出:抽取10% 要求一天20000块以上才接 if(money > 20000f){ rtValue = method.invoke(actor,money*0.9f); } } return rtValue; } }); ? ? proxyActor.basicAct(10000f); proxyActor.dangerAct(50000f); } } ?
运行结果:
拿到钱,开始基本的表演:8000.0拿到钱,开始危险的表演:45000.0
总结:
动态代理基于接口 * 作用:不修改源码的基础上,对已有方法增强 * 特点:字节码是随用随创建,随用随加载。 * 基于接口的动态代理: * 提供者:JDK官方 * 要求:被代理对象最少实现一个接口。 * 涉及的类:Proxy * 涉及的方法:newProxyInstance * 方法的参数: * ClassLoader:类加载器。负责加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 * Class[]:字节码数组。代理对象具有的方法。和被代理对象实现相同的接口。 * 如果被代理对象本身是一个接口的话,直接把被代理对象存入字节码数组中。 * xxx.getClass().getInterfaces() || new Class[]{xxx} * 固定写法。 * InvocationHandler:如何代理的接口。谁用谁写。用于增强方法的。需要我们自己提供一个该接口的实现类。 * 通常情况下可以写成匿名内部类。 * 策略模式: * 数据已经有了 * 目的明确。 * 达成目标的过程即是策略。
1.2基于子类的动态代理
public class Actor { ? /** * 基本表演 * @param money */ ? public void basicAct(Float money){ System.out.println("拿到钱,开始基本的表演cglib:"+money); } ? /** * 危险的表演 */ ? public void dangerAct(Float money){ System.out.println("拿到钱,开始危险的表演cglib:"+money); } } ? ? ? ? public class Client { ? public static void main(String[] args) { // 早期:直接去家里找 // Actor actor = new Actor(); // 通过经纪公司来找演员 /** * 动态代理 * 作用:不修改源码的基础上,对已有方法增强 * 特点:字节码是随用随创建,随用随加载。 * 基于子类的动态代理: * 提供者:第三方cglib库 * 要求:被代理对象不能是最终类。不能被final修饰 * 涉及的类:Enhancer * 涉及的方法:create * 方法的参数: * Class:字节码。被代理对象的字节码。固定写法。 ? * Callback:如何代理的接口。谁用谁写。用于增强方法的。需要我们自己提供一个该接口的实现类。 * 通常情况下可以写成匿名内部类。 * 我们需要使用它的子接口:MethodInterceptor * 策略模式: * 数据已经有了 * 目的明确。 * 达成目标的过程即是策略。 * */ Actor cglibActor = (Actor) Enhancer.create(actor.getClass(), new MethodInterceptor() { /** * 此处提供增强的代码 * 执行被代理对象的任何方法,都会经过该方法。 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前方法所需的参数 * @param methodProxy 当前方法的代理对象 * @return 和被代理对象的方法具有相同的返回值 * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object rtValue = null; // 1.取出当前方法的参数 Float money= (Float) args[0]; // 2.判断方法是什么 if("basicAct".equals(method.getName())){ // 基本演出:抽取20% 要求一天5000块以上才接 if(money > 5000f){ rtValue = method.invoke(actor,money*0.75f); } } if("dangerAct".equals(method.getName())){ // 高危演出:抽取10% 要求一天20000块以上才接 if(money > 20000f){ rtValue = method.invoke(actor,money*0.85f); } } return rtValue; } }); cglibActor.basicAct(10000f); cglibActor.dangerAct(50000f); } }
原文地址:https://www.cnblogs.com/mudi/p/9844536.html
时间: 2024-10-15 04:37:40