Java 动态代理实现
创建 Java 的动态代理需要使用 Proxy 类:
// code 8 java.lang.reflect.Proxy
调用它的 newProxyInstance 方法,就可以为某类创建一个代理类。例如给 Map 创建一个代理类:
// code 9 Map mapProxy = (Map) Proxy.newProxyInstance( HashMap.class.getClassLoader(), new Class[]{Map.class}, new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { return null; } } );
可以分析下这个方法,方法签名为:
// code 10 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- ClassLoader 类型的 loader 对象:被代理类的类加载器;
- Class 数组的 interfaces 对象:被代理的接口,对应于之前关键词中的 被代理的行为,这里传入的是接口而不是某个具体的类,所以表示行为;
- InvocationHandler 接口对象 h:代理的具体的行为,对应之前关键词中的 对行为的完全控制,这也是 Java 动态代理的核心;
- 返回的 Object 对象:对应之前关键词中的 代理对象。
所以,要实现一个动态代理大概需要下面几个步骤:
一、定义要被代理的行为 例如 code1 就是定义的要被代理的行为。
二、定义被代理的对象 就是实现了接口的类,例如实现了租房流程的房东,详见 code2。
三、建立代理关系 这个是代理的核心,需要一个实现了 InvocationHandler 接口的类:
// code 11 public class AgentHandler implements InvocationHandler { private Object target; public AgentHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法执行前"); Object result = method.invoke(target, args); System.out.println("方法执行后"); return result; } }
接口中的 invoke 方法比较重要。方法体中的 Object 类型的 proxy 是最终生成的代理对象;Method 类型的 method 是被代理的方法;Object[] 数组类型的 args 是被代理方法执行所需要的参数。target 对象就是传入的代理类。在这个类中,可以在 invoke 方法前后插入我们需要执行的代码,这样做可以使得被代理类对象在执行任何方法时,都会执行我们插入的代码。例如,我们可以在 invoke 方法前后记录下时间戳,这样就可以得出被代理类对象执行的每一个方法的执行时长。
然后代理类利用 InvocationHandler 进行代理:
// code 12 public class HouseAgentSmart { private IRentHouse mHouseOwner; // 房东,被代理类对象 public HouseAgentSmart(IRentHouse houseOwner) { mHouseOwner = houseOwner; mHouseOwner = (IRentHouse) Proxy.newProxyInstance( houseOwner.getClass().getClassLoader(), new Class[]{IRentHouse.class}, new AgentHandler(mHouseOwner) // 将被代理对象传入 ); } public IRentHouse getAccess() { // 用于返回代理对象 return mHouseOwner; } }
四、执行者调用
// code 13 IRentHouse smartAgent = new HouseAgentSmart(new HouseOwner()).getAccess(); smartAgent.visitHouse(); smartAgent.argueRent(400); smartAgent.signAgreement();
Kotlin 动态代理实现
上面是动态代理的 Java 实现,那么如何用 Kotlin 实现? 其实是一样的,只不过是编程语言的语法不同
// code 14 // IRentHouseKT.kt 1、首先还是定义接口 interface IRentHouseKT { // 带领租客看房 fun visitHouse() // 讨价还价 fun argueRent(rent : Int) // 签合同 fun signAgreement() } // HouseOwnerKT.kt 2、然后是被代理类,实现接口 class HouseOwnerKT : IRentHouseKT { override fun visitHouse() { println("HouseOwner 带领看房,介绍房屋特点") } override fun argueRent(rent: Int) { println("HouseOwner 提出租金为:$rent") } override fun signAgreement() { println("HouseOwner 签合同") } } // AgentHandlerKT.kt 3、建立代理关系 class AgentHandlerKT : InvocationHandler { private var mTarget : Any? = null constructor(target : Any?) { this.mTarget = target } override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? { println("方法执行前") // 因为传来的参数 args 是不确定的,所以用 *args.orEmpty() 传参 val result = method.invoke(mTarget, *args.orEmpty()) println("方法执行后") return result } } // HouseAgentSmartKT.kt 4、代理类,通过 AgentHandlerKT 得到代理关系 class HouseAgentSmartKT { var mHouseOwner : IRentHouseKT? = null constructor(houseOwner : IRentHouseKT) { mHouseOwner = houseOwner mHouseOwner = Proxy.newProxyInstance( houseOwner.javaClass.classLoader, arrayOf(IRentHouseKT::class.java), AgentHandlerKT(mHouseOwner) ) as IRentHouseKT } } // 调用方进行调用 val smartAgent = HouseAgentSmartKT(HouseOwnerKT()).mHouseOwner smartAgent?.visitHouse() smartAgent?.argueRent(500) smartAgent?.signAgreement()
看到这里就有人要问了,咦?之前不是用 by 关键字就可以在 kotlin 中进行代理吗?为啥还需要像 Java 一样用 Proxy.newProxyInstance() 方法写代理的模式?这两种方式有什么区别?
首先,这两种方式都可以在 Kotlin 中实现代理模式,但适用的场景有所不同。 1、by 关键字实现的代理模式。使用起来更加方便,代理的粒度更小,可以根据代理类自身需要对某些被代理类中的方法进行重写; 2、Proxy.newProxyInstance() 方法实现的代理模式。实现比较繁琐,代理的粒度大,一旦代理,就是代理所有的方法。可以在原方法前后插入自己想要执行的代码,适用于埋点记录 log 日志、记录方法执行用时等。
参考文献
- Java动态代理——框架中的应用场景和基本原理
- 当Kotlin邂逅设计模式之代理模式(二)
还没看够?欢迎来逛逛我的公众号。搜索:修之竹也欢迎知乎关注 修之竹~
ps. 赠人玫瑰,手留余香。欢迎转发分享加关注,你的认可是我继续创作的精神源泉。