作者:京东零售 秦浩然
举个栗子,众所周知,我们是可以在京东上购买机票的。 但机票是航司提供的,我们本质上是代理销售而已。
那为什么航司要让我们代理销售呢?
我们又是如帮他做代理的呢?
别急,本文将展开说说他们之间的关系。。。
从前有个航司打算开展线上销售机票业务,于是设计了如下系统。系统完成后,业务正常开展了。。。
航司销售机票的接口:
1 2 3 4 5 6 7 8 | public interface SellAirTicket { / * * * 销售机票 * @param price * / void sellAirTicket( int price); } |
航司销售机票的接口实现类:
1 2 3 4 5 6 7 | public class SellAirTicketImpl implements SellAirTicket { @Override public void sellAirTicket( int price) { System.out.println( "航司销售机票,价格:" + price); } } |
测试:
1 2 3 4 5 6 7 | public class MainClass { public static void main(String[] args) { SellAirTicket sellAirTicket = new SellAirTicketImpl(); sellAirTicket.sellAirTicket( 666 ); } } |
测试结果:
1 | 航司销售机票,价格: 666 |
随着业务发展的越来越好,新的问题出现了。
黄牛天天爬接口,系统风险出现了;卖完票没有统计结果,卖成啥样也不知道。
于是航司想增加售前风控、售后统计。加上这些功能后,业务又继续稳步发展了。。。
航司销售机票的接口:
1 2 3 4 5 6 7 8 | public interface SellAirTicket { / * * * 销售机票 * @param price * / void sellAirTicket( int price); } |
航司销售机票的接口实现类:
1 2 3 4 5 6 7 8 9 | public class SellAirTicketImpl implements SellAirTicket { @Override public void sellAirTicket( int price) { System.out.println( "航司售前风控。。。" ); System.out.println( "航司销售机票,价格:" + price); System.out.println( "航司售后统计。。。" ); } } |
测试:
1 2 3 4 5 6 7 | public class MainClass { public static void main(String[] args) { SellAirTicket sellAirTicket = new SellAirTicketImpl(); sellAirTicket.sellAirTicket( 666 ); } } |
测试结果:
1 2 3 | 航司售前风控。。。 航司销售机票,价格: 666 航司售后统计。。。 |
后来航司发现,就这么点人,又想做风控,又想卖机票,又想做统计,根本忙不过来。
那怎么解决呢? 航司只想专心卖票,不想做这些跟卖票无关的工作,那只能找个代理公司了。
于是,航司找到了JD代替自己做这些工作,自己就负责专心卖票。。。
航司销售机票的接口:
1 2 3 4 5 6 7 8 | public interface SellAirTicket { / * * * 销售机票 * @param price * / void sellAirTicket( int price); } |
航司销售机票的接口实现类:
1 2 3 4 5 6 7 | public class SellAirTicketImpl implements SellAirTicket { @Override public void sellAirTicket( int price) { System.out.println( "航司销售机票,价格:" + price); } } |
JD平台代理航司销售机票实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class SellAirTicketProxy implements SellAirTicket { / * * * 航司售票接口 * / private SellAirTicket sellAirTicket; @Override public void sellAirTicket( int price) { System.out.println( "JD售前风控。。。" ); sellAirTicket.sellAirTicket(price); System.out.println( "JD售后统计。。。" ); } public SellAirTicketProxy(SellAirTicket sellAirTicket) { this.sellAirTicket = sellAirTicket; } } |
测试:
1 2 3 4 5 6 7 8 | public class MainClass { public static void main(String[] args) { SellAirTicket sellAirTicket = new SellAirTicketImpl(); SellAirTicket sellAirTicketProxy = new SellAirTicketProxy(sellAirTicket); sellAirTicketProxy.sellAirTicket( 666 ); } } |
测试结果:
1 2 3 | JD售前风控。。。 航司销售机票,价格: 666 JD售后统计。。。 |
以上流程对与航司而言,由JD帮助自己关注风控、统计,自已可以专心的卖票,看着很好的样子。
但是JD平台只能给航司卖票,其余的也干不了,航司与JD的关系属于静态绑定的关系,即:被代理类与代理类属于静态绑定的关系,称之为“静态代理”。
据此,我们可以给代理模式下个定义:
1 2 3 4 5 6 7 8 9 | 【代理模式】 就是在不改变原有类(被代理类)的情况下,为原有类创建代理对象,对原有类的功能做增强的一种模式 代理模式的优点: 1. 满足单一原则,业务类可以只关心自己的核心逻辑,非核心逻辑由代理类完成; 2. 易于维护,核心逻辑、非核心逻辑的修改不会互相影响; 3. 对于用户(调用者)而言,使用的方式没有区别,有和可以做到低成本替换; 代理模式的缺点: 1. 每个被代理类都要有一个代理类,大大增加了代码量; |
某天,保险公司也被风控、统计逻辑搞的焦头烂额,听说航司找了个代理,于是也找到了JD,让JD给他们做代理。
JD想:总不能谁来找我,我就给谁做一套代理系统吧,那我得做多少套,反正他们都是找我做风控、统计的,那我能不能做一套系统,给他们所有的人用呢,说干就干。。。
保险公司销售保险的接口:
1 2 3 4 5 6 7 8 | public interface SellInsurance { / * * * 销售保险 * @param price * / void sellInsurance( int price); } |
保险公司销售保险的接口实现类:
1 2 3 4 5 6 7 | public class SellInsuranceImpl implements SellInsurance { @Override public void sellInsurance( int price) { System.out.println( "保险公司销售保险,价格:" + price); } } |
JD平台代理的风控、统计实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class SellDynamicProxy { / * * * 获取传入目标对象的代理对象 * @param target * @ return * / public Object createProxy( Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), / / 目标对象使用类加载器 target.getClass().getInterfaces(), / / 目标对象实现的接口的类型 new DynamicProxyHandler(target)); / / 目标对象事件处理器 } / * * * 目标对象的事件处理器 * / private class DynamicProxyHandler implements InvocationHandler { / / 被代理对象 private Object target; @Override public Object invoke( Object proxy, Method method, Object [] args) throws Throwable { System.out.println( "JD售前风控。。。" ); method.invoke(target, args); System.out.println( "JD售后统计。。。" ); return null; } public DynamicProxyHandler( Object object ) { this.target = object ; } } } |
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class MainClass { public static void main(String[] args) { / / 创建动态代理平台 SellDynamicProxy dynamicProxy = new SellDynamicProxy(); / / 代理销售机票 SellAirTicket airTicketProxy = (SellAirTicket) dynamicProxy.createProxy(new SellAirTicketImpl()); airTicketProxy.sellAirTicket( 600 ); / / 代理销售保险 SellInsurance insuranceProxy = (SellInsurance) dynamicProxy.createProxy(new SellInsuranceImpl()); insuranceProxy.sellInsurance( 30 ); } } |
测试结果:
1 2 3 4 5 6 | JD售前风控。。。 航司销售机票,价格: 600 JD售后统计。。。 JD售前风控。。。 保险公司销售保险,价格: 30 JD售后统计。。。 |
到这里航司、保险公司都找到了自己的代理,JD平台也完成了风控、统计代理平台的搭建。再有人来找自己,JD平台都可以满足代理需求,现在看来,已经很完美了。
被代理的商家与JD属于动态绑定的关系,即:被代理类与代理类属于动态绑定的关系,称之为“动态代理”,由于此代理功能依赖JDK提供的Proxy、InvocationHandler类,也成为“JDK动态代理”。
据此,我们可以补充代理模式的定义:
1 2 3 4 5 6 7 8 9 10 11 | 【代理模式】 就是在不改变原有类(被代理类)的情况下,为原有类创建代理对象,对原有类的功能做增强的一种模式 代理模式的优点: 1. 满足单一原则,业务类可以只关心自己的核心逻辑,非核心逻辑由代理类完成; 2. 易于维护,核心逻辑、非核心逻辑的修改不会互相影响; 3. 对于用户(调用者)而言,使用的方式没有区别,可以做到低成本替换; 4. JDK动态代理可以动态的绑定目标类,可以减少代码量,提高代码的复用; 代理模式的缺点: 1. 静态代理每个被代理类都要有一个代理类,大大增加了代码量; 2. JDK动态代理基于JDK的反射原理实现,降低了执行效率; |
平静的日子没过多久,一天某酒店找来了,要求给他们做代理,做就做呗。轻车又熟路。。。
酒店销售房间:
1 2 3 4 5 6 7 8 9 10 | public class SellHotel { / * * * 销售酒店 * @param price * / public void sellHotel( int price) { System.out.println( "酒店销售房间,价格:" + price); } } |
测试:
1 2 3 4 5 6 7 8 9 10 | public class MainClass { public static void main(String[] args) { / / 创建动态代理平台 SellDynamicProxy dynamicProxy = new SellDynamicProxy(); / / 代理销售酒店 SellHotel sellHotel = (SellHotel) dynamicProxy.createProxy(new SellHotel()); sellHotel.sellHotel( 300 ); } } |
测试结果:
1 2 | Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to demo.pattern.proxy.SellHotel at demo.pattern.proxy.MainClass.main(MainClass.java: 14 ) |
怎么回事,平台不好用了!代理公司闭关修炼,查一下问题。。。
以前给别人代理都好使,这次给酒店代理为何就不行了呢? 一个优秀的代理,有问题就要解决问题。。。
先看异常,代理类不能被强转为目标类型,但是为何之前的都好使?
思考:只有生成的代理类属于目标类型,才能强转,那就需要代理类实现目标类的接口,那问题就可能是这样了,验证一下。
让我们先看下源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | / * * * 获取传入目标对象的代理对象 * @param target * @ return * / public Object createProxy( Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), / / 目标对象使用类加载器 target.getClass().getInterfaces(), / / 目标对象实现的接口的类型 new DynamicProxyHandler(target)); / / 目标对象事件处理器 } / * * * 创建代理类源码 * / public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm ! = null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } / * * Look up or generate the designated proxy class . * / Class<?> cl = getProxyClass0(loader, intfs); / / 生成代理类的字节码对象 / * * Invoke its constructor with the designated invocation handler. * / try { if (sm ! = null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); / / 获取参数为事件处理器的构造器 final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object []{h}); / / 用词构造器,传入的事件处理器,构造代理类 } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } / * * * Generate a proxy class . Must call the checkProxyAccess method * to perform permission checks before calling this. * 生成代理类的字节码对象 * / private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535 ) { throw new IllegalArgumentException( "interface limit exceeded" ); } / / If the proxy class defined by the given loader implementing / / the given interfaces exists, this will simply return the cached copy; / / otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); / / 这里获取字节码对象 } / * * * 这里获取字节码对象 * / public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); / / lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap< Object , Supplier<V>> valuesMap = map .get(cacheKey); if (valuesMap = = null) { ConcurrentMap< Object , Supplier<V>> oldValuesMap = map .putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap ! = null) { valuesMap = oldValuesMap; } } / / create subKey and retrieve the possible Supplier<V> stored by that / / subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory. apply (key, parameter)); / / 这里创建字解码对象 Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier ! = null) { / / supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); if (value ! = null) { return value; } } / / else no supplier in cache / / or a supplier that returned null (could be a cleared CacheValue / / or a Factory that wasn't successful in installing the CacheValue) / / lazily construct a Factory if (factory = = null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier = = null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier = = null) { / / successfully installed Factory supplier = factory; } / / else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { / / successfully replaced / / cleared CacheEntry / unsuccessful Factory / / with our Factory supplier = factory; } else { / / retry with current supplier supplier = valuesMap.get(subKey); } } } } / * * * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. * * Proxy类的内部类,就是为了创建代理对象的字节码对象 * / private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { / / prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy" ; / / next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply (ClassLoader loader, Class<?>[] interfaces) { Map <Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { / * * Verify that the class loader resolves the name of this * interface to the same Class object . * / Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass ! = intf) { throw new IllegalArgumentException( intf + " is not visible from class loader" ); } / * * Verify that the Class object actually represents an * interface. * / if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface" ); } / * * Verify that this interface is not a duplicate. * / if (interfaceSet.put(interfaceClass, Boolean.TRUE) ! = null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; / / package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; / * * Record the package of a non - public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non - public proxy interfaces are in the same package. * / for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf( '.' ); String pkg = ((n = = - 1 ) ? "" : name.substring( 0 , n + 1 )); if (proxyPkg = = null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages" ); } } } if (proxyPkg = = null) { / / if no non - public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "." ; } / * * Choose a name for the proxy class to generate. * / long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; / * * Generate the specified proxy class . * / byte[] proxyClassFile = ProxyGenerator.generateProxyClass( / / 这里生成需要的字节码对象 proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0 , proxyClassFile.length); } catch (ClassFormatError e) { / * * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). * / throw new IllegalArgumentException(e.toString()); } } } |
上面分析一堆,那我们来了看看得到的代理类到底是啥,为啥他就能执行那个我们的目标类的方法。同时,还得目标类实现接口?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | / * * * 我们自己生成一份目标类字节码文件 * @throws IOException * / public static void transClass() throws IOException { SellAirTicketImpl sellAirTicket = new SellAirTicketImpl(); byte[] bts = ProxyGenerator.generateProxyClass( "$Proxy0" , sellAirTicket.getClass().getInterfaces()); File file = new File ( "E:\test" , "$Proxy0.class" ); if (! file .exists()){ file .createNewFile(); } FileOutputStream fos = new FileOutputStream( file ); fos.write(bts); fos.flush(); fos.close(); } |
将我们的字节码文件在此反编译:http://javare.cn,得到我们的代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | import demo.pattern.proxy.SellAirTicket; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements SellAirTicket { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler var1) throws { / / 代理类的构造器,将事件处理器传入,交给父类Proxy super (var1); } public final boolean equals( Object var1) throws { try { return ((Boolean) super .h.invoke(this, m1, new Object []{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String) super .h.invoke(this, m2, ( Object [])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void sellAirTicket( int var1) throws { try { super .h.invoke(this, m3, new Object []{Integer.valueOf(var1)}); / / 执行目标方法时,调用父类的事件处理器 } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final int hashCode() throws { try { return ((Integer) super .h.invoke(this, m0, ( Object [])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName( "java.lang.Object" ).getMethod( "equals" , new Class[]{Class.forName( "java.lang.Object" )}); m2 = Class.forName( "java.lang.Object" ).getMethod( "toString" , new Class[ 0 ]); m3 = Class.forName( "demo.pattern.proxy.SellAirTicket" ).getMethod( "sellAirTicket" , new Class[]{Integer. TYPE }); / / 获取接口类型的目标方法 m0 = Class.forName( "java.lang.Object" ).getMethod( "hashCode" , new Class[ 0 ]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } } |
到此为止真相大白了,原来代理类继承了Proxy父类,同时实现了目标类的接口,这就将我们的目标方法与定义的事件处理器联系起来了。
同时,由于java的单继承模式,导致了代理类只能继承Proxy类,那这样的话,就只好通过目标类的接口来关联目标类了。
据此,我们可以再次补充代理模式的定义:
1 2 3 4 5 6 7 8 9 10 11 12 | 【代理模式】 就是在不改变原有类(被代理类)的情况下,为原有类创建代理对象,对原有类的功能做增强的一种模式 代理模式的优点: 1. 满足单一原则,业务类可以只关心自己的核心逻辑,非核心逻辑由代理类完成; 2. 易于维护,核心逻辑、非核心逻辑的修改不会互相影响; 3. 对于用户(调用者)而言,使用的方式没有区别,可以做到低成本替换; 4. JDK动态代理可以动态的绑定目标类,可以减少代码量,提高代码的复用; 代理模式的缺点: 1. 静态代理每个被代理类都要有一个代理类,大大增加了代码量; 2. JDK动态代理基于JDK的反射原理实现,降低了执行效率; 3. JDK动态代理是基于接口的代理,要求目标类必须实现目标接口; |
到这里,问题是搞明白了,就是酒店的问题,但是好的合作伙伴就是应该不抛弃,不放弃。
酒店跟我们合作,我们就要帮助他们解决困难。那怎么办呢?酒店没接口,JDK代理又非要接口,那我们就不用JDK代理了!
这时,基于类的代理方式就应运而生了—— cglib为我们提供了基于类的动态代理模式。
导Jar包:cglib-3.2.5.jar(cglib核心包)、asm-3.3.1.jar(字节码处理框架)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class CglibDynamicProxy implements MethodInterceptor { / / 目标对象 private Object target; / * * * 给目标对象创建一个代理对象 * / public Object getProxyInstance(){ / / 工具类 Enhancer en = new Enhancer(); / / 设置父类 en.setSuperclass(target.getClass()); / / 设置回调函数 en.setCallback(this); / / 创建子类代理对象 return en.create(); } @Override public Object intercept( Object o, Method method, Object [] objects, MethodProxy methodProxy) throws Throwable { System.out.println( "cglib售前风控。。。" ); final Object invoke = method.invoke(target, objects); System.out.println( "cglib售后统计。。。" ); return invoke; } public CglibDynamicProxy( Object target) { this.target = target; } } |
测试
1 2 3 4 5 6 | public static void main(String[] args) { / / 创建销售酒店代理 CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(new SellHotel()); SellHotel sellHotel = (SellHotel) cglibDynamicProxy.getProxyInstance(); sellHotel.sellHotel( 300 ); } |
测试结果
1 2 3 | cglib售前风控。。。 酒店销售房间,价格: 300 cglib售后统计。。。 |
那为啥cglib就不用目标类实现接口了呢?让我们看看代理类。
1 2 3 4 5 6 7 8 | public static void main(String[] args) { / / 代理类 class 文件存入本地磁盘 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\testCglib" ); / / 创建销售酒店代理 CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(new SellHotel()); SellHotel sellHotel = (SellHotel) cglibDynamicProxy.getProxyInstance(); sellHotel.sellHotel( 300 ); } |
反编译结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | / * * * 代理类反编译结果 * / public class SellHotel$$EnhancerByCGLIB$$ 2624d6e3 extends SellHotel implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; / / 方法拦截器 private static final Method CGLIB$sellHotel$ 0 $Method; / / 被代理方法 private static final MethodProxy CGLIB$sellHotel$ 0 $Proxy; / / 代理方法 private static final Object [] CGLIB$emptyArgs; private static final Method CGLIB$equals$ 1 $Method; private static final MethodProxy CGLIB$equals$ 1 $Proxy; private static final Method CGLIB$toString$ 2 $Method; private static final MethodProxy CGLIB$toString$ 2 $Proxy; private static final Method CGLIB$hashCode$ 3 $Method; private static final MethodProxy CGLIB$hashCode$ 3 $Proxy; private static final Method CGLIB$clone$ 4 $Method; private static final MethodProxy CGLIB$clone$ 4 $Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object [ 0 ]; Class var0 = Class.forName( "demo.pattern.proxy.SellHotel$$EnhancerByCGLIB$$2624d6e3" ); / / 代理类 Class var1; / / 被代理类 CGLIB$sellHotel$ 0 $Method = ReflectUtils.findMethods(new String[]{ "sellHotel" , "(I)V" }, (var1 = Class.forName( "demo.pattern.proxy.SellHotel" )).getDeclaredMethods())[ 0 ]; CGLIB$sellHotel$ 0 $Proxy = MethodProxy.create(var1, var0, "(I)V" , "sellHotel" , "CGLIB$sellHotel$0" ); Method[] var10000 = ReflectUtils.findMethods(new String[]{ "equals" , "(Ljava/lang/Object;)Z" , "toString" , "()Ljava/lang/String;" , "hashCode" , "()I" , "clone" , "()Ljava/lang/Object;" }, (var1 = Class.forName( "java.lang.Object" )).getDeclaredMethods()); CGLIB$equals$ 1 $Method = var10000[ 0 ]; CGLIB$equals$ 1 $Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z" , "equals" , "CGLIB$equals$1" ); CGLIB$toString$ 2 $Method = var10000[ 1 ]; CGLIB$toString$ 2 $Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;" , "toString" , "CGLIB$toString$2" ); CGLIB$hashCode$ 3 $Method = var10000[ 2 ]; CGLIB$hashCode$ 3 $Proxy = MethodProxy.create(var1, var0, "()I" , "hashCode" , "CGLIB$hashCode$3" ); CGLIB$clone$ 4 $Method = var10000[ 3 ]; CGLIB$clone$ 4 $Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;" , "clone" , "CGLIB$clone$4" ); } final void CGLIB$sellHotel$ 0 ( int var1) { super .sellHotel(var1); } public final void sellHotel( int var1) { / / 代理类重写的方法 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; / / 方法拦截器 if (this.CGLIB$CALLBACK_0 = = null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 ! = null) { / / 执行方法拦截器 var10000.intercept(this, CGLIB$sellHotel$ 0 $Method, new Object []{new Integer(var1)}, CGLIB$sellHotel$ 0 $Proxy); } else { super .sellHotel(var1); } } final boolean CGLIB$equals$ 1 ( Object var1) { return super .equals(var1); } public final boolean equals( Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 = = null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 ! = null) { Object var2 = var10000.intercept(this, CGLIB$equals$ 1 $Method, new Object []{var1}, CGLIB$equals$ 1 $Proxy); return var2 = = null?false:((Boolean)var2).booleanValue(); } else { return super .equals(var1); } } final String CGLIB$toString$ 2 () { return super .toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 = = null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 ! = null?(String)var10000.intercept(this, CGLIB$toString$ 2 $Method, CGLIB$emptyArgs, CGLIB$toString$ 2 $Proxy): super .toString(); } final int CGLIB$hashCode$ 3 () { return super .hashCode(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 = = null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 ! = null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$ 3 $Method, CGLIB$emptyArgs, CGLIB$hashCode$ 3 $Proxy); return var1 = = null? 0 :((Number)var1).intValue(); } else { return super .hashCode(); } } final Object CGLIB$clone$ 4 () throws CloneNotSupportedException { return super .clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (this.CGLIB$CALLBACK_0 = = null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 ! = null?var10000.intercept(this, CGLIB$clone$ 4 $Method, CGLIB$emptyArgs, CGLIB$clone$ 4 $Proxy): super .clone(); } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case - 508378822 : if (var10000.equals( "clone()Ljava/lang/Object;" )) { return CGLIB$clone$ 4 $Proxy; } break ; case 1826985398 : if (var10000.equals( "equals(Ljava/lang/Object;)Z" )) { return CGLIB$equals$ 1 $Proxy; } break ; case 1913648695 : if (var10000.equals( "toString()Ljava/lang/String;" )) { return CGLIB$toString$ 2 $Proxy; } break ; case 1979480752 : if (var10000.equals( "sellHotel(I)V" )) { return CGLIB$sellHotel$ 0 $Proxy; } break ; case 1984935277 : if (var10000.equals( "hashCode()I" )) { return CGLIB$hashCode$ 3 $Proxy; } } return null; } public SellHotel$$EnhancerByCGLIB$$ 2624d6e3 () { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS. set (var0); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } private static final void CGLIB$BIND_CALLBACKS( Object var0) { SellHotel$$EnhancerByCGLIB$$ 2624d6e3 var1 = (SellHotel$$EnhancerByCGLIB$$ 2624d6e3 )var0; if (!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 = = null) { var10000 = CGLIB$STATIC_CALLBACKS; if (CGLIB$STATIC_CALLBACKS = = null) { return ; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[ 0 ]; } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); SellHotel$$EnhancerByCGLIB$$ 2624d6e3 var10000 = new SellHotel$$EnhancerByCGLIB$$ 2624d6e3 (); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); SellHotel$$EnhancerByCGLIB$$ 2624d6e3 var10000 = new SellHotel$$EnhancerByCGLIB$$ 2624d6e3 (); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object [] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); SellHotel$$EnhancerByCGLIB$$ 2624d6e3 var10000 = new SellHotel$$EnhancerByCGLIB$$ 2624d6e3 ; switch(var1.length) { case 0 : var10000.<init>(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException( "Constructor not found" ); } } public Callback getCallback( int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch(var1) { case 0 : var10000 = this.CGLIB$CALLBACK_0; break ; default: var10000 = null; } return var10000; } public void setCallback( int var1, Callback var2) { switch(var1) { case 0 : this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2; default: } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[ 0 ]; } static { CGLIB$STATICHOOK1(); } } |
到此,我们知道cglib代理是帮我们新建了一个代理类,此代理类继承自目标类获取目标方法,同时重写了目标方法。
再通过我们定义的拦截器调用我们的目标方法,以此来达到代理目标方法的目的。
据此,我们可以总结代理模式的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 【代理模式】 就是在不改变原有类(被代理类)的情况下,为原有类创建代理对象,对原有类的功能做增强的一种模式。 代理模式的优点: 1. 满足单一原则,业务类可以只关心自己的核心逻辑,非核心逻辑由代理类完成; 2. 易于维护,核心逻辑、非核心逻辑的修改不会互相影响; 3. 对于用户(调用者)而言,使用的方式没有区别,可以做到低成本替换; 4. JDK动态代理可以动态的绑定目标类,可以减少代码量,提高代码的复用; 5. cglib动态代理可基于实现类做代理,可以解决JDK代理依赖接口的问题; 代理模式的缺点: 1. 静态代理每个被代理类都要有一个代理类,大大增加了代码量; 2. JDK动态代理基于JDK的反射原理实现,降低了执行效率; 3. JDK动态代理是基于接口的代理,要求目标类必须实现目标接口; 代理模式分类: 1. 静态代理; 2. JDK动态代理(基于目标类的接口生成代理类做代理); 3. cglib动态代理(基于目标类生成子类做代理,同时也支持基于接口的代理); |
我们知道,Spring的AOP就是依赖于动态代理模式实现的,那我们在日常的开发中有哪些地方能用到代理呢?
•事物
•日志
•监控
•统计
•鉴权
•限流
•缓存
•环境隔离