Spring-AOP
java
類,並被編譯從新加載,而後在新的類中執行目標業務實現動態代理。CGLib和JDK-proxy
的區別。
JDK-proxy
動態代理:實現了被代理對象的接口,生成新的class字節碼,利用反射調用實現代理。沒法代理不實現代理業務接口的方法。CGLib
動態代理:繼承被代理對象,生成新的class字節碼,經過fastclass
機制調用實現代理。沒法代理被final關鍵字修飾的方法爲其餘對象提供一種代理,以控制對這個對象的訪問。代理對象在客戶端和服務端起到中介的做用。是一種結構型設計模式。java
/** * @description: 被代理對象須要實現的目標接口 * @author: lmc * @create: 2019-06-12 15:38 **/ public interface ITarget { /** * @description: 被代理對象的行爲 * @return void * @date 2019/6/12 15:39 * @author lmc */ void behavior(); }
/** * @description: 真實的被代理的目標對象 * @author: lmc * @create: 2019-06-12 15:41 **/ public class TargetImpl implements ITarget { public void behavior() { System.out.println("執行真實的被代理對象的行爲。"); } }
下面的類也是一個被代理的目標對象,可是沒有實現ITarget
接口設計模式
/** * @description: 真實的被代理的目標對象 * @author: lmc * @create: 2019-06-12 15:41 **/ public class Target{ public void behavior() { System.out.println("執行被代理對象target的行爲。"); } }
/** * @description: 靜態代理類 * @author: lmc * @create: 2019-06-12 15:45 **/ public class StaticProxy { /** * 持有被代理對象的引用 */ private ITarget targetImpl; /** * 持有被代理對象的引用 */ private Target target;//一個沒有實現接口的類 /** * 構造方法初始化值 * @param targetImpl */ public StaticProxy(ITarget targetImpl,Target target){ this.targetImpl=targetImpl; this.target=target; } /** * @description: 被代理以前的加強行爲 * @date 2019/6/12 15:56 * @author lmc */ private void beforeBehavior(){ System.out.println("執行代理以前須要作的一些事情。"); } /** * @description: 被代理以後的加強行爲 * @date 2019/6/12 15:57 * @author lmc */ private void afterBehavior(){ System.out.println("執行代理以後須要作的一些事情。"); } /** * @description: 開始執行代理 * @date 2019/6/12 15:59 * @author lmc */ public void startProxy(){ beforeBehavior(); targetImpl.behavior(); target.behavior(); afterBehavior(); } }
/** * @description: 靜態代理客戶端 懶漢式單例 * @author: lmc * @create: 2019-06-12 16:01 **/ public class StaticProxyClient implements Serializable { private final static StaticProxyClient staticProxyClient=new StaticProxyClient(); private StaticProxyClient(){ if(null != staticProxyClient){ throw new RuntimeException("單例類,不容許被反射實例化"); } }; public static StaticProxyClient getInstance(){ return staticProxyClient; } /** * @description: 開始靜態代理 * @date 2019/6/12 16:20 * @author lmc */ public void startStaticProxy(){ ITarget targetImpl=new TargetImpl(); Target target=new Target(); StaticProxy staticProxy=new StaticProxy(targetImpl,target); staticProxy.startProxy(); } /** * @description: 重寫readResolve,防止序列化破壞單例 * @return java.lang.Object * @date 2019/6/12 16:18 * @author lmc */ private Object readResolve(){ return staticProxyClient; } }
/** * @description: 靜態代理測試 * @author: lmc * @create: 2019-06-12 16:10 **/ public class StaticProxyTest { public static void main(String[] args) { StaticProxyClient.getInstance().startStaticProxy(); } }
只要代理對象持有被代理對象的引用就能夠實現靜態代理了。ide
JDK-proxy
動態代理/** * @description: 真實的被代理的目標對象 * @author: lmc * @create: 2019-06-12 15:41 **/ public class TargetImpl1 implements ITarget { public void behavior() { System.out.println("執行被代理對象1的行爲。"); } }
/** * @description: 真實的被代理的目標對象 * @author: lmc * @create: 2019-06-12 15:41 **/ public class TargetImpl2 implements ITarget { public void behavior() { System.out.println("執行被代理對象2的行爲。"); } }
/** * @description: 真實的被代理的目標對象 * @author: lmc * @create: 2019-06-12 15:41 **/ public class TargetImpl3 implements ITarget { public void behavior() { System.out.println("執行被代理對象3的行爲。"); } }
/** * @description: JDK動態代理對象 * @author: lmc * @create: 2019-06-12 17:00 **/ public class JdkProxy implements InvocationHandler { /** * 被代理對象的引用 */ private ITarget target; /** * @description: 獲取代理以後的實例對象 * @param target 被代理對象 * @return com.lmc.gp12380.pattern.proxy.ITarget * @date 2019/6/12 19:55 * @author lmc */ public ITarget getProxyInstance(ITarget target){ this.target = target; Class<?> clazz = target.getClass(); return (ITarget) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeBehavior(); //經過反編譯工具能夠查看源代碼 byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{ITarget.class}); FileOutputStream os = new FileOutputStream("E://$Proxy0.class"); os.write(bytes); os.close(); Object obj = method.invoke(this.target,args); afterBehavior(); return obj; } /** * @description: 被代理以前的加強行爲 * @date 2019/6/12 15:56 * @author lmc */ private void beforeBehavior(){ System.out.println("執行代理以前須要作的一些事情。"); } /** * @description: 被代理以後的加強行爲 * @date 2019/6/12 15:57 * @author lmc */ private void afterBehavior(){ System.out.println("執行代理以後須要作的一些事情。"); } }
下面這個類是測試沒有實現ITarget
接口的代理工具
/** * @description: JDK動態代理對象 * @author: lmc * @create: 2019-06-12 17:00 **/ public class JdkProxy1 implements InvocationHandler { /** * 被代理對象的引用 */ private Target target; /** * @description: 獲取代理以後的實例對象 * @param target 被代理對象 * @return com.lmc.gp12380.pattern.proxy.ITarget * @date 2019/6/12 19:55 * @author lmc */ public Target getProxyInstance(Target target){ this.target = target; Class<?> clazz = target.getClass(); return (Target) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeBehavior(); //經過反編譯工具能夠查看源代碼 byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{ITarget.class}); FileOutputStream os = new FileOutputStream("E://$Proxy0.class"); os.write(bytes); os.close(); Object obj = method.invoke(this.target,args); afterBehavior(); return obj; } /** * @description: 被代理以前的加強行爲 * @date 2019/6/12 15:56 * @author lmc */ private void beforeBehavior(){ System.out.println("執行代理以前須要作的一些事情。"); } /** * @description: 被代理以後的加強行爲 * @date 2019/6/12 15:57 * @author lmc */ private void afterBehavior(){ System.out.println("執行代理以後須要作的一些事情。"); } }
下面這個類是Jdk-proxy
代理生成的class字節碼反編譯以後的java
類學習
public final class $Proxy0 extends Proxy implements ITarget { public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } public final boolean equals(Object obj) { try { return ((Boolean) super.h.invoke(this, m1, new Object[]{ obj })).booleanValue(); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } return false; } public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } return null; } public final void behavior() { try { super.h.invoke(this, m3, null); return; } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Error _ex) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } return 0; } private static Method m1; private static Method m2; private static Method m3; private static Method m0; 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("com.lmc.gp12380.pattern.proxy.ITarget").getMethod("behavior", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } }
這裏咱們知道了這個反編譯生成的java
類實現了ITarget
接口測試
/** * @description: JDK代理實現測試 * @author: lmc * @create: 2019-06-12 19:49 **/ public class JdkProxyTest { public static void main(String[] args) { ITarget target1 = (ITarget) new JdkProxy().getProxyInstance(new TargetImpl1()); target1.behavior(); ITarget target2 = (ITarget) new JdkProxy().getProxyInstance(new TargetImpl2()); target2.behavior(); ITarget target3 = (ITarget) new JdkProxy().getProxyInstance(new TargetImpl3()); target3.behavior(); /** * Target 類沒有實現接口 沒法被jdkproxy代理 */ ITarget target4 = (ITarget) new JdkProxy1().getProxyInstance(new Target()); target4.behavior(); } }
JDK-proxy
動態代理測試結果嘿嘿,能夠看到target4
代理出錯啦。緣由就是Target
類沒有實現ITarget
接口。this
CGLib
動態代理/** * @description: CGLib動態代理對象 * @author: lmc * @create: 2019-06-12 17:00 **/ public class CGLibProxy implements MethodInterceptor { /** * @description: 被代理以前的加強行爲 * @date 2019/6/12 15:56 * @author lmc */ private void beforeBehavior(){ System.out.println("執行代理以前須要作的一些事情。"); } /** * @description: 被代理以後的加強行爲 * @date 2019/6/12 15:57 * @author lmc */ private void afterBehavior(){ System.out.println("執行代理以後須要作的一些事情。"); } /** * @description: 獲取代理以後的實例對象 * @param target 被代理對象 * @return com.lmc.gp12380.pattern.proxy.ITarget * @date 2019/6/12 19:55 * @author lmc */ public Object getProxyInstance(Object target){ Class<?> clazz = target.getClass(); //至關於Proxy,代理的工具類 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { beforeBehavior(); /** * 利用 cglib 的代理類能夠將內存中的 class 文件寫入本地磁盤 */ System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cglib_proxy_class/"); Object obj = methodProxy.invokeSuper(o,objects); afterBehavior(); return obj; } }
/** * @description: CGLib代理實現測試 * @author: lmc * @create: 2019-06-12 20:26 **/ public class CGLibProxyTest { public static void main(String[] args) { ITarget target1= (ITarget) new CGLibProxy().getProxyInstance(new TargetImpl1()); target1.behavior(); ITarget target2= (ITarget) new CGLibProxy().getProxyInstance(new TargetImpl2()); target2.behavior(); ITarget target3= (ITarget) new CGLibProxy().getProxyInstance(new TargetImpl3()); target3.behavior(); Target target4= (Target) new CGLibProxy().getProxyInstance(new Target()); target4.behavior(); } }
CGLib動態代理測試結果
嘿嘿,能夠看到Target沒有實現ITarget
接口,也能實現動態代理。設計
代碼裏面是能夠生成CGLib
動態代理的字節碼文件的,也能夠反編譯過來看看,由於我是看不懂,我就不展現了。3d