Java代理(jdk靜態代理、動態代理和cglib動態代理)
代理模式是常用的java設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託類的物件的相關方法,來提供特定的服務。
一. JDK 動態代理
1.業務介面(必須有)
package com.sww.proxy;
public interface HelloWorldJDKProxy {
void helloWorld();
}
2.業務實現
package com.sww.proxy;
/**
* JDK 動態代理測試
*
* @author TF12778 2019/1/28 09:49
*/
public class HelloWorldJDKProxyImpl implements HelloWorldJDKProxy {
public void helloWorld() {
System.out.println("Hello World JDK Proxy!");
}
}
3.代理類
package com.sww.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK動態代理
*
* @author TF12778 2019/1/28 09:52
*/
public class JDKInvocationHandler implements InvocationHandler {
private Object target;
public JDKInvocationHandler(Object target){
this.target = target;
}
/**
* 建立代理例項
* @return
* @throws Throwable
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), this.target.getClass()
.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method:" + method.getName() + " is invoked!");
return method.invoke(target, args);
}
}
4. JDK動態代理測試
package com.sww.proxy;
/**
* JAVA JDK動態代理
*
* 代理是Java常用的設計模式,代理類通過呼叫被代理類的相關方法,並對相關方法進行增強。加入一些非業務性程式碼,比如事務、日誌、報警發郵件等操作。
*
* @author TF12778 2019/1/28 09:44
*/
public class ProxyController {
public static void main(String[] atgs){
/**
* JDK 動態代理
*/
HelloWorldJDKProxy jdkProxy = new HelloWorldJDKProxyImpl();
JDKInvocationHandler handle = new JDKInvocationHandler(jdkProxy);
// 根據目標生成代理物件
HelloWorldJDKProxy proxy = (HelloWorldJDKProxy)handle.getProxy();
proxy.helloWorld();
}
}
測試結果:
method:helloWorld is invoked!
Hello World JDK Proxy!
二. CGLib 動態代理
1. 業務實現(可以沒有業務介面類)
package com.sww.proxy;
/**
* 業務類
* 沒有實現介面
* 如果類是final的,則沒法生成代理物件,報錯。
* 如果方法是final的,代理無效
*
*
* @author TF12778 2019/1/28 10:31
*/
public class HelloWorldCGlibImpl {
public void showCGLibMsg() {
System.out.println("CGLibMsg Test Success");
}
}
2. 代理類
package com.sww.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 使用Cglib動態代理
*
* @author TF12778 2019/1/28 10:35
*/
public class CGlibMethodInterceptor implements MethodInterceptor
{
private Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 設定回掉方法
enhancer.setCallback(this);
// 建立代理物件
return enhancer.create();
}
/**
*
* @param o
* @param method
* @param objects
* @param 實現MethodInterceptor介面要重寫的方法
* @return
* @throws 回撥方法
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("事物開始。。。。。。");
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("事物結束。。。。。。");
return result;
}
}
3. 測試
package com.sww.proxy;
/**
* JAVA JDK動態代理
*
* 代理是Java常用的設計模式,代理類通過呼叫被代理類的相關方法,並對相關方法進行增強。加入一些非業務性程式碼,比如事務、日誌、報警發郵件等操作。
*
* @author TF12778 2019/1/28 09:44
*/
public class ProxyController {
public static void main(String[] atgs){
/**
* CGLib 動態代理
*/
CGlibMethodInterceptor cglibProxy = new CGlibMethodInterceptor();
HelloWorldCGlibImpl HelloCGlibImpl = (HelloWorldCGlibImpl)cglibProxy.getInstance(new HelloWorldCGlibImpl());
HelloCGlibImpl.showCGLibMsg();
}
}
測試結果:
事物開始。。。。。。
CGLibMsg Test Success
事物結束。。。。。。
三、總結
1、原理
jdk靜態代理實現比較簡單,一般是直接代理物件直接包裝了被代理物件。
jdk動態代理是介面代理,被代理類A需要實現業務介面,業務代理類B需要實現InvocationHandler介面。
jdk動態代理會根據被代理物件生成一個繼承了Proxy類,並實現了該業務介面的jdk代理類,該類的位元組碼會被傳進去的ClassLoader載入,建立了jdk代理物件例項,
jdk代理物件例項在建立時,業務代理物件例項會被賦值給Proxy類,jdk代理物件例項也就有了業務代理物件例項,同時jdk代理物件例項通過反射根據被代理類的業務方法建立了相應的Method物件m(可能有多個)。當jdk代理物件例項呼叫業務方法,如proxy.addUser();這個會先把對應的m物件作為引數傳給invoke()方法(就是invoke方法的第二個引數),呼叫了jdk代理物件例項的invoke()回撥方法,在invoke方法裡面再通過反射來呼叫被代理物件的因為方法,即result = method.invoke(target, args);。
cglib動態代理是繼承代理,通過ASM位元組碼框架修改位元組碼生成新的子類,重寫並增強方法的功能。
2、優缺點
jdk靜態代理類只能為一個被代理類服務,如果需要代理的類比較多,那麼會產生過多的代理類。jdk靜態代理在編譯時產生class檔案,執行時無需產生,可直接使用,效率好。
jdk動態代理必須實現介面,通過反射來動態代理方法,消耗系統效能。但是無需產生過多的代理類,避免了重複程式碼的產生,系統更加靈活。
cglib動態代理無需實現介面,通過生成子類位元組碼來實現,比反射快一點,沒有效能問題。但是由於cglib會繼承被代理類,需要重寫被代理方法,所以被代理類不能是final類,被代理方法不能是final。
因此,cglib的應用更加廣泛一點。
相關文章
- 代理模式詳解:靜態代理、JDK動態代理與Cglib動態代理模式JDKCGLib
- 靜態代理和動態代理(jdk/cglib)詳解JDKCGLib
- JDK動態代理和 CGLIB 代理JDKCGLib
- JDK動態代理和CGLib代理JDKCGLib
- java靜態代理和動態代理Java
- 3.靜態代理&動態代理&CGlibCGLib
- Java動態代理(JDK和cglib)JavaJDKCGLib
- JAVA 靜態代理 & 動態代理Java
- Java進階之 JDK動態代理與Cglib動態代理JavaJDKCGLib
- 靜態代理和動態代理
- spring aop原理 JDK動態代理和CGLIB動態代理SpringJDKCGLib
- Java中的靜態代理和動態代理Java
- 你必須會的 JDK 動態代理和 CGLIB 動態代理JDKCGLib
- 深入理解靜態代理與JDK動態代理JDK
- cglib動態代理和jdk動態代理的區別與應用CGLibJDK
- Java基礎系列-靜態代理和動態代理Java
- (轉)Java動態代理與CGLib代理JavaCGLib
- 最詳細的代理講解--JDK動態代理和cglib代理JDKCGLib
- 輕鬆理解 Java 靜態代理/動態代理Java
- CGLib 動態代理CGLib
- JAVA學習篇--靜態代理VS動態代理Java
- java執行原理、靜態代理和動態代理區分Java
- AOP之靜態代理VS動態代理
- jdk的動態代理和靜態代理你還寫不出來嘛???JDK
- JDK動態代理JDK
- 動態代理jdk和cglib的區別JDKCGLib
- Spring動態代理的生成-如何判斷是使用JDK動態代理還是CGlib代理SpringJDKCGLib
- Java 靜態代理和動態代理的使用及原理解析Java
- Java JDK Proxy和CGLib動態代理示例講解JavaJDKCGLib
- 靜態代理、動態代理與Mybatis的理解MyBatis
- 動態代理-cglib分析CGLib
- Java代理之靜態代理Java
- JDK動態代理初探JDK
- Java動態代理 jdk和cglib的實現比較JavaJDKCGLib
- 由《尋秦記》說代理模式(靜態,動態,CGLib)模式CGLib
- JDK 和 CGLib 實現動態代理和區別JDKCGLib
- Java設計模式學習06——靜態代理與動態代理Java設計模式
- 代理模式 - 動態代理模式