Spring AOP - Java Dynamic Proxy and CGLib
主題: |
Spring AOP - Java Dynamic Proxy and CGLib |
文章簡介: |
Spring會依照不同設定實作AOP,本文介紹其中的兩種實作機制Java Dynamic Proxy和CGLib Proxy及其限制。 |
作者: |
胡育群 |
版本/產出日期: |
V1.0/2016.12.12 |
1. 前言
• AOP(Aspect-Oriented Programming)可將散落在各個商務流程中的共同邏輯集結成獨立可重用的服務,且不會與應用程式發生耦合,隨時可抽換。
• Spring在AOP上的應用很多,會依據設定使用不同機制實現。目前支援三種機制:Java Dynamic Proxy、CGLib Proxy、AspectJ,本文利用簡單的應用介紹前面兩種Proxy機制。
2. 目的
• 了解Spring在不同設定下對AOP的實作機制及其限制,利於專案初期規劃,避免日後重構。
3. 開始前準備
本架構建立於以下版本的環境:
• JDK8
• STS 3.6.2.RELEASE
• Maven3.2.1(STS 3.6.2中內建)
4. Java Dynamic Proxy
4.1、 物件關聯
圖 1、Java Dynamic Proxy Class diagram
• Proxy(java.lang.reflect.Proxy)在執行期創建實作DemoService介面的$Proxy物件。
• $Proxy物件關聯至InvocationHandlerImpl,進行攔截。
• InvocationHandlerImpl需擁有被代理的DemoServiceImpl1物件,才能呼叫到需執行的功能。
4.2、 作業流程
圖 2、Java Dynamic Proxy Control flow
• 所有被$Proxy實作到的功能,呼叫時會先被dispatch到關聯的InvocationHandlerImpl中的invoke。
• invoke執行加入的服務模組,再呼叫被代理的DemoServiceImpl1物件中原有功能。
4.3、 依照圖 1實現Demo程式
圖 3、DemoService - 被代理的物件實作的介面
圖 4、DemoServiceImpl1 - 被代理的物件
圖 5、JavaDynamicProxySample1 - 流程Demo
圖 6、Console log - JavaDynamicProxySample1 Run on Java Application
4.4、 歸納出Java Dynamic Proxy有以下幾點限制
• 無法攔截static method。
• 無法攔截未定義在介面上的method,換言之只能攔截public method。
• 無法攔截內部呼叫method。
5. CGLib Proxy
5.1、 物件關聯
圖 7、CGLib Proxy Class diagram
• CGLib Proxy Enhancer(org.springframework.cglib.proxy.Enhancer)在執行期創建繼承DemoServiceImpl2的DemoServiceImpl2$$EnhancerByCGLIB$$物件。
• DemoServiceImpl2$$EnhancerByCGLIB$$物件關聯至MethodInterceptorImpl,進行攔截。
5.2、 作業流程
圖 8、CGLib Proxy Control flow
5.3、 依照圖 7實現Demo程式
圖 9、DemoServiceImpl2 - 被代理的物件
圖 10、CGLibProxySample1 - 流程Demo
圖 11、Console log - CGLibProxySample2 Run on Java Application
5.4、 歸納出CGLib Proxy有以下幾點限制
• 無法攔截static method。
• 無法攔截無法繼承的method。
• 無法攔截內部呼叫method。
6. Spring AOP設定
6.1、 Spring要用哪一種AOP實作機制決定要素
• 若被攔截的bean有繼承介面,使用Java Dynamic Proxy,反之被攔截bean未繼承任何介面,則會使用CGLib Proxy。
• Java config可以在bean上加@Scope,強制使用何種Proxy,如圖 9,DemoServiceImpl2雖然有繼承DemoService介面,但是使用CGLib Proxy實作。
• Xml config 可以加上scoped-proxy或proxy-target-class屬性來決定使用何種方式實作。
6.2、 Demo程式
圖 12、pom.xml - maven設定
圖 13、PointcutDefinition - Pointcut定義
圖 14、LoggerAspect - 定義需要動態加入的服務
圖 15、SpringAopSample1Application - Demo Spring AOP use Spring Boot
• DemoService參考圖 3。
• DemoServiceImpl1參考圖 4。
• DemoServiceImpl2參考圖 9。
圖 16、Console log - SpringAopSample1Application Run on Java Application
7. Proxy機制限制及解決方法
7.1、 Proxy機制限制
Proxy機制是在執行期間創建一個Proxy類別,所以有以下限制
• 無法攔截不能繼承的method
• Java Dynamic Proxy為介面繼承,只能繼承public method。
• CGLib為類別繼承,不能繼承private or static method。
• 無法攔截內部呼叫method(沒有經過Proxy類別)。
7.2、 解決辦法
使用AspectJ進行程式碼的織入,支援compile time、load time weaving。
8. 參考來源
• AOP概念-
http://openhome.cc/Gossip/SpringGossip/AOPConcept.html
• Java Dynamic Proxy-
https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
• CGLib Proxy -
https://github.com/cglib/cglib
• Spring AOP-http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
• Spring proxy pitfalls -
http://www.nurkiewicz.com/2011/10/spring-pitfalls-proxying.html