javascript
浅谈Spring的AOP实现-代理机制
說起Spring的AOP(Aspect-Oriented Programming)面向切面編程大家都很熟悉(Spring不是這次博文的重點),但是我先提出幾個問題,看看同學們是否了解,如果了解的話可以不用繼續往下讀:
1. Spring的AOP的實現方式有哪些?
2. 為什么使用代理機制?
3. 它們是怎么實現的?
4. 它們的區別是什么?
下面進入正題,Spring采用代理的方式實現AOP,具體采用了JDK的動態代理和CGLib實現。使用動態代理和CGLib的目的是在現有類的基礎上增加一些功能。簡單地將就是有一個Proxy類,實現了原始類的方法,并且在原始類的基礎上增加了新的功能。那么這么做可以實現很多功能:
1. 在方法前后進行日志處理。
2. 進行額外的校驗,比如參數的驗證功能等。
3. 實現一些懶加載,也就是實例化的時候如果不去調用真正的方法的時候,這個類的屬性就不會存在(Hibernate有這樣類似的功能)。
下面咱們用簡單的代碼實現它是如何進行代理的,首先采用的是JDK的動態代理實現:
定義一個接口:
package com.hqs.proxy;/*** 操作系統光接口* @author hqs**/ public interface OpSystem {public void work(); }定義一個實現類:
package com.hqs.proxy;/*** Mac 的實現* @author hqs**/ public class Mac implements OpSystem {public void work() {System.out.println("Mac is running"); }}關鍵位置來了,我們通過實現JDK自帶的反射機制的包的InvocationHandler來進行反射處理,實現它之后需要實現里邊的invoke方法,這個invoke方法里邊的參數分別為:代理類實例,用于調用method的;method參數是實際執行的方法;args所傳輸的參數數組。
package com.hqs.proxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class OpHandler implements InvocationHandler {private final OpSystem ops; public OpHandler(OpSystem ops) {this.ops = ops;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before system running");method.invoke(ops, args);System.out.println("After system running");return null;}public static void main(String[] args) {Mac mac = new Mac();OpHandler oph = new OpHandler(mac);OpSystem os = (OpSystem)Proxy.newProxyInstance(oph.getClass().getClassLoader(),mac.getClass().getInterfaces(), oph);os.work();System.out.println(os.getClass());}}輸出: Before system running Mac is running After system running class com.sun.proxy.$Proxy0? 然后看到里邊的main方法中,代理類實例化對象的方法Proxy.newProxyInstance,這個是JDK的反射方法去實例化代理類,其中有三個參數分別是,去實例化代理類的class loader;所代理的類的所有接口Class數組;hander處理類,用于做攔截使用的類。最后我輸出了一下os.getClass(),大家可以看到的是代理類的實例,而不是真正代理類的實例,這么做的好處就是很方便的復用這個代理類,比如你可以重復調用它而不用去重新實例化新類,再一點就是你可以針對不同的方法進行攔截,比如你可以method.getName()去判斷調用的方法名字是什么從而更細粒度的攔截方法。咱們繼續看用CGLib的實現:
package com.hqs.proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;/*** CGLib Interceptor用于方法攔截* @author hqs**/ public class CGLibInterceptor implements MethodInterceptor {private final Mac mac;public CGLibInterceptor(Mac mac) {this.mac = mac;}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("Before system running");method.invoke(mac, args);System.out.println("After system running");return null;}public static void main(String[] args) {Mac mac = new Mac(); //實例而非接口MethodInterceptor handler = new CGLibInterceptor(mac);Mac m = (Mac)Enhancer.create(mac.getClass(), handler);m.work();System.out.println(m.getClass());}}輸出: Before system running Mac is running After system running class com.hqs.proxy.Mac$$EnhancerByCGLIB$$1f2c9d4a首先需要引入cglib包,然后才能使用他的MethodInterptor,它也采用method.invoke實現對代理類的調用。它的代理類創建采用Enhancer的create方法,其中傳入了需要創建的類的class,以及Callback對象,因為MethodInterceptor繼承了Callback對象。用于指向方法前后進行調用的類。
public interface MethodInterceptor extends Callback這是這兩個類的基本實現,那么它們的區別是什么呢?
這些是它們的根本區別,但是Spring推薦使用JDK的動態代理,面向接口去編程。使用CGLib去做代理的時候需要注意,它生成的代理類存放在JVM的Perm space里邊,那么是不是生成的代理對象就不進行回收了?其實不是的,不經常回收但是還是回收的,當類被加載,加載類的classLoader什么時候變得對垃圾回收可用的時候才進行回收。也就是你自己創建所有類移除classLoader之后,那么這個classLoader就會被回收,一般非常精通CGLib的話可以進行這塊內容深入開發,因為它可以做出amzing的事情如果你熟悉的話。
如果有不對的地方歡迎拍磚~
轉載于:https://www.cnblogs.com/huangqingshi/p/7651376.html
總結
以上是生活随笔為你收集整理的浅谈Spring的AOP实现-代理机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: StringBuilder String
- 下一篇: Python爬虫入门四之Urllib库的