java 动态代理(JDK和cglib)
设计模式这东东每次看到就明确可过段时间又不能非常流利的说出来。今天就用具体的比喻和实例来加深自己的理解(小弟水平不高有不正确的地方希望大家能指出来)。
(1)代理这个词生活中有非常多比方在街边卖手机卡、充公交地铁卡的小商店他们都起了代理的作用,java中的代理跟这些小店商的作用是一样的。
再比方我想在淘宝上开个服装店但又没有货源怎么办,这时候我就要跟淘宝上某一卖家联系做他的代理。我跟我的商家都要卖衣服(就好比我们都继承了卖衣服的接口sellClothesInterface),我的商家能够卖他网店上的衣服跟我没的关系(就好比实现了sellClothesInterface接口),我的网店也能够卖代理的衣服(同都也实现了sellClothesInterface接口),这个时候买家从我的网店上买了一件衣服而衣服的发货地址确是我的商家的,买家跟我的商家没有不论什么关系,我就起了代理的作用。
(2)用官方的话:代理模式是经常使用的java设计模式,他的特征是代理类与托付类有相同的接口,代理类主要负责为托付类预处理消息、过滤消息、把消息转发给托付类,以及事后处理消息等。代理类与托付类之间一般会存在关联关系,一个代理类的对象与一个托付类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用托付类的对象的相关方法,来提供特定的服务。
(3)代理分为两种:静态代理和动态代理。
1、静态代理用代码实现例如以下:
public interface SellClothesInterface { // 都能卖衣服的接口 public void sell(); }
public class BossSellClothes implements SellClothesInterface { // 我的商家有卖衣服的方法 public void sell() { System.out.println("确定信息并发货..."); } }
public class MySellClothes implements SellClothesInterface { private BossSellClothes bossSellClothes; // 构造方法 public MySellClothes(BossSellClothes bossSellClothes) { this.bossSellClothes = bossSellClothes; } public void sell() { // 卖衣服之前先与买家做沟通确定下单 System.out.println("确认信息。确定下单..."); bossSellClothes.sell(); // 买家收货并打款 System.out.println("买家收到货交易结束..."); } }
@org.junit.Test public void run1() { BossSellClothes bossSellClothes = new BossSellClothes();// 我的商家实例类 SellClothesInterface scif = new MySellClothes(bossSellClothes);// 我卖衣服类 scif.sell();// 卖衣服 }
执行结果:
确认信息,确定下单...
确定信息并发货...
买家收到货交易结束...
从上面代码能够发现每个代理类仅仅能为一个接口服务。所有的代理操作除了调用的方法不一样之外,其它的操作都一样,则此时肯定是反复代码。解决这一问题最好的做法是能够通过一个代理类完毕所有的代理功能,那么此时就必须使用动态代理完毕。
2、动态代理
JDK动态代理中包括一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所须要的參数
能够将InvocationHandler接口的子类想象成一个代理的终于操作类,也就是上面静态代理类MySellClothes。
Proxy类:
Proxy类是专门完毕代理的操作类,能够通过此类为一个或多个接口动态地生成实现类,此类提供了例如以下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
參数说明:
ClassLoader loader:类载入器,用于找到被代理类。
Class<?>[] interfaces:得到所有的接口 。被代理类实现的所有接口。
InvocationHandler h:得到InvocationHandler接口的子类实。
代码修改发下:
/** * JDK动态代理 * * @author Administrator * */ public class SellClothesProxy implements InvocationHandler { private Object target; /** * 传入被代理类生成代理类 * * @param target * @return */ public Object buildProxy(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 调用方法 */ 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; } }
@org.junit.Test public void run2() { // 创建代理类并调用方法 SellClothesProxy proxy = new SellClothesProxy(); SellClothesInterface scif = (SellClothesInterface) proxy.buildProxy(new BossSellClothes()); scif.sell(); }
执行结果:
确认信息,确定下单...
确定信息并发货...
买家收到货交易结束...
结果出来了,但有一个问题继承InvocationHandler 覆盖invoke方法。那这种方法什么时候被调用的呢?,打个断点发现scif.sell();执行时才调用invoke方法。这个invoke 方法返回一个 Object的实例,然会会强转成你须要的接口。这时候调用你这个接口的方法的时候, 实质上 就是执行了 这个invoke的方法。
(4)cglib动态代理
有了JDK的动态代理再说说cglib。为什么要用cglib呢。JDK的动态代理依靠接口实现,假设有些类并没有实现接口。则不能使用JDK代理,cglib就弥补了这点。cglib是对指定的目标类生成一个子类,并覆盖当中方法实现增强。但既然是类的继承就不能对final修饰的类进行代理了。
public class SellClothesProxy2 implements MethodInterceptor { private Object target; /** * 传入被代理类生成代理类 * * @param target * @return */ public Object buildProxy(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("确认信息。确定下单..."); proxy.invokeSuper(obj, args); System.out.println("买家收到货交易结束..."); return null; } }
@org.junit.Test public void run3() { SellClothesProxy2 proxy = new SellClothesProxy2(); SellClothesInterface scif = (SellClothesInterface) proxy.buildProxy(new BossSellClothes()); scif.sell(); }
执行结果:
确认信息,确定下单...
确定信息并发货...
买家收到货交易结束...