动态代理常用的有两种方式
注:以下以演员演出作为例子:1. 直接找演员表演;2. 找到中介后,由中介寻找演员演出(中介需赚取佣金)。(其实与租房是类似的,找房东直租和找中介租房两种方式。)
基于接口的动态代理
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。
- IActor.java
public interface IActor { boolean baseAct(float money); // 基础演出 boolean dangerAct(float money); // 危险演出 }
- Actor.java
public class Actor implements IActor { @Override public boolean baseAct(float money) { System.out.println("基础演出收入:"+money); return true; } @Override public boolean dangerAct(float money) { System.out.println("危险演出收入:"+money); return true; } }
- ProxyTest.java
/** * 使用 JDK 官方的 Proxy 类创建代理对象 * 基于接口的动态代理 * 提供者:JDK 官方的 Proxy 类。 * 要求:被代理类最少实现一个接口。 */ public class ProxyTest { public static void main(String[] args) { Actor actor = new Actor(); IActor proxyActor = proxyFun(actor); actor.baseAct(1000); actor.dangerAct(10000); proxyActor.baseAct(1000); proxyActor.dangerAct(10000); } public static IActor proxyFun(Actor actor) { /* * 创建的方式: * Proxy.newProxyInstance(三个参数) * 参数含义: * ClassLoader:和被代理对象使用相同的类加载器。 * Interfaces:和被代理对象具有相同的行为。实现相同的接口。 * InvocationHandler:如何代理。 */ IActor proxyActor = (IActor) Proxy.newProxyInstance( actor.getClass().getClassLoader(), actor.getClass().getInterfaces(), new InvocationHandler() { /** * 执行被代理对象的任何方法,都会经过该方法。因此有拦截功能。 * @param proxy: 代理对象的引用。 * @param method: 外部所调用的方法,已封装为方法对象。 * @param args: 外部调用方法时传递的参数列表。 * @return 执行该方法后的返回值 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); float money = (float) args[0]; Object rtValue = null; if ("baseAct".equals(name)) { rtValue = method.invoke(actor,money/2); } if ("dangerAct".equals(name)) { rtValue = method.invoke(actor, money/2); } return rtValue; } } ); return proxyActor; } }
- 运行结果
基于子类的动态代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
- Actor.java
public class Actor { public boolean baseAct(float money) { System.out.println("基础演出收入:"+money); return true; } public boolean dangerAct(float money) { System.out.println("危险演出收入:"+money); return true; } }
- EnhancerTest.java
/** * 使用 CGLib 的 Enhancer 类创建代理对象 * 基于子类的动态代理 * 提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。 * 要求:被代理类不能用 final 修饰的类(最终类)。 */ public class EnhancerTest { public static void main(String[] args) { Actor actor = new Actor(); Actor enhancerActor = EnhancerFun(actor); actor.baseAct(1000); actor.dangerAct(10000); enhancerActor.baseAct(1000); enhancerActor.dangerAct(10000); } public static Actor EnhancerFun(Actor actor) { /* * 创建的方式: * Enhancer.create(Class, Callback) * 参数的含义: * Class:被代理对象的字节码 * Callback:如何代理(使用MethodInterceptor接口实现类代理)。 */ Actor enhancerActor = (Actor) Enhancer.create(actor.getClass(), new MethodInterceptor() { /** * 执行被代理对象的任何方法,都会经过该方法。因此有拦截功能。 * @param proxy: 代理对象的引用。 * @param method: 外部所调用的方法,已封装为方法对象。 * @param args: 外部调用方法时传递的参数列表。 * @param methodProxy: 当前执行方法的代理对象。 * @return 执行该方法后的返回值 */ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { String name = method.getName(); float money = (float) args[0]; Object rtValue = null; if ("baseAct".equals(name)) { rtValue = method.invoke(actor,money/2); } if ("dangerAct".equals(name)) { rtValue = method.invoke(actor, money/2); } return rtValue; } }); return enhancerActor; } }
- 运行结果