java动态代理 1. 简介
java的动态代理功能是用来解决现有类功能不足,但我们又不想去修改现有类方法的问题,或者就是我们无法直接使用现有类的情况。它的实现方式有两种,第一种是jdk自带的动态代理功能,它的实现前提是现有类必须拥有一个接口,因为它是通过对现有类接口的实现来完成的。第二种方式是cglib,这是一个开源工具包,它的实现是通过继承现有类,然后重写现有类的方法实现的。它们在spring与mybatis框架中均有使用。学习它们的前提是你要对java的反射机制有一定的认知。本篇只介绍jdk原生的动态代理。
2. jdk动态代理 2.1 演示前景客户:购买u盘
代理商:淘宝
u盘工厂:金士顿,三星等
用户想要购买u盘,是不可以直接去厂家购买的,需要通过淘宝等代理商进行购买,抽象成程序就是,u盘工程就是目标类,也就是现有类,淘宝就是代理类,客户就是用户类.用户需要调用淘宝的方法进行购买u盘,而淘宝又需要调用工厂的方法进行购买.如果我们直接创建一个淘宝类,让它去代理金士顿工厂,就会出现一个问题,那就是三星工厂由谁去代理,总不能再创建一个代理类吧,所以就可以使用动态代理的方式,在程序运行时期,根据不同的情况去创建一个合适的代理类
2.2编写代码首先我们需要一个工厂的接口UsbFactory
package com.hzq.application.targetclass; public interface UsbFactory { //售卖u盘,并返回实际价格的方法 float sell(int num); }第二步就是创建一个UsbFactory的实现类UsbKingFactory代表金士顿工厂
package com.hzq.application.targetclass.impl; import com.hzq.application.targetclass.UsbFactory; public class UsbKingFactory implements UsbFactory { @Override public float sell(int num) { float onePrice = 30.0F; float price = onePrice * num; System.out.println("向厂家购买花费了"+price+"元"); return price; } }现在需要我们代理的目标类已经好了,接下来就是重点了,jdk动态代理的实现方法(这个实现套路是固定的)。第三步,创建一个MyInvocationHandler类去实现接口InvocationHandler。这个接口只有一个需要我们去实现的方法,那就是invoke()方法,它有3个参数,第一个参数其实就是我们后面通过动态代理去创建的代理类,这个参数不需要我们的参与,不用去理会,第二个参数是我们要去增强的目标类的方法,第三个是该方法的参数.invoke内部就是我们要对目标类的方法增强的具体逻辑,也就是我们想怎样去增强它,在本示例中我们是对用户购买的商品收取20元中介费,然后送给用户一张10元的优惠券
package com.hzq.application.proxy; import com.hzq.application.targetclass.UsbFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private UsbFactory factory ; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //1.调用目标类的售卖方法,然后返回价格 Float price = (Float) method.invoke(factory, args); //2.我们在之后进行自定义的增强,这里我们是抽取20元的中介费用,然后送给客户一张10元优惠券 price += 20; System.out.println("代理商送您一张10元优惠券"); System.out.println("客户购买商品花费了"+price+"元"); return price; } public MyInvocationHandler(UsbFactory factory) { this.factory = factory; } }最后一步就是去使用jdk动态代理来在运行期创建一个代理类对象了,在代码中第第三步是重点,我们如果我们想要创建一个动态代理类,就必须要调用Proxy类的静态方法newProxyInStance()方法,这个方法会返回给我们一个代理类对象,我们实际购买商品也是通过这个代理类来进行购买的。newProxyInstance()方法一共有三个参数,第一个参数是一个类加载器对象,类加载器对象可以通过目标类的Class对象去调用getClassLoader()方法去获取,其实也可以使用其他你自定义的类的Class对象去获取,因为最后获得的都是同一个类加载器实例,但为了代码的易读性,就使用了目标类。第二个参数是目标类的接口类型,第三个参数就是我们自定义的MyInvocationHandler类的实例对象了,它里面封装这我们具体的增强逻辑代码。方法调用完成后,如果没有出现问题就会返回给我们一个代理类的实例,之后我们就可以去使用这个代理类的。
package com.hzq.application; import com.hzq.application.proxy.MyInvocationHandler; import com.hzq.application.targetclass.UsbFactory; import com.hzq.application.targetclass.impl.UsbKingFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyMain { public static void main(String[] args) { //1.实例化一个金士顿工厂对象 UsbFactory usbFactory = new UsbKingFactory(); //2.实例化一个MyInvocationHandler对象 InvocationHandler handler = new MyInvocationHandler(usbFactory); //3.通过jdk动态代理创建出代理对象 UsbFactory proxyInstance = (UsbFactory) Proxy.newProxyInstance(usbFactory.getClass().getClassLoader(), usbFactory.getClass().getInterfaces(), handler); //4.通过代理对象来购买商品 float price = proxyInstance.sell(3); System.out.println(price); } }