Java動態代理(JDK和cglib)
JAVA的動態代理
代理模式
代理模式是常用的java設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託類的物件的相關方法,來提供特定的服務。
按照代理的建立時期,代理類可以分為兩種。
靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。
動態代理:在程式執行時,運用反射機制動態建立而成。
首先看一下靜態代理:
1、Count.java
Java程式碼
- package net.battier.dao;
- /**
- * 定義一個賬戶介面
- *
- * @author Administrator
- *
- */
- public interface Count {
- // 檢視賬戶方法
- public void queryCount();
- // 修改賬戶方法
- public void updateCount();
- }
2、CountImpl.java
Java程式碼
- package net.battier.dao.impl;
- import net.battier.dao.Count;
- /**
- * 委託類(包含業務邏輯)
- *
- * @author Administrator
- *
- */
- public class CountImpl implements Count {
- @Override
- public void queryCount() {
- System.out.println("檢視賬戶方法...");
- }
- @Override
- public void updateCount() {
- System.out.println("修改賬戶方法...");
- }
- }
- 、CountProxy.java
- package net.battier.dao.impl;
- import net.battier.dao.Count;
- /**
- * 這是一個代理類(增強CountImpl實現類)
- *
- * @author Administrator
- *
- */
- public class CountProxy implements Count {
- private CountImpl countImpl;
- /**
- * 覆蓋預設構造器
- *
- * @param countImpl
- */
- public CountProxy(CountImpl countImpl) {
- this.countImpl = countImpl;
- }
- @Override
- public void queryCount() {
- System.out.println("事務處理之前");
- // 呼叫委託類的方法;
- countImpl.queryCount();
- System.out.println("事務處理之後");
- }
- @Override
- public void updateCount() {
- System.out.println("事務處理之前");
- // 呼叫委託類的方法;
- countImpl.updateCount();
- System.out.println("事務處理之後");
- }
- }
3、TestCount.java
Java程式碼
- package net.battier.test;
- import net.battier.dao.impl.CountImpl;
- import net.battier.dao.impl.CountProxy;
- /**
- *測試Count類
- *
- * @author Administrator
- *
- */
- public class TestCount {
- public static void main(String[] args) {
- CountImpl countImpl = new CountImpl();
- CountProxy countProxy = new CountProxy(countImpl);
- countProxy.updateCount();
- countProxy.queryCount();
- }
- }
觀察程式碼可以發現每一個代理類只能為一個介面服務,這樣一來程式開發中必然會產生過多的代理,而且,所有的代理操作除了呼叫的方法不一樣之外,其他的操作都一樣,則此時肯定是重複程式碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那麼此時就必須使用動態代理完成。
再來看一下動態代理:
JDK動態代理中包含一個類和一個介面:
InvocationHandler介面:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
引數說明:
Object proxy:指被代理的物件。
Method method:要呼叫的方法
Object[] args:方法呼叫時所需要的引數
可以將InvocationHandler介面的子類想象成一個代理的最終操作類,替換掉ProxySubject。
Proxy類:
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個介面動態地生成實現類,此類提供瞭如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
引數說明:
ClassLoader loader:類載入器
Class<?>[] interfaces:得到全部的介面
InvocationHandler h:得到InvocationHandler介面的子類例項
Ps:類載入器
在Proxy類中的newProxyInstance()方法中需要一個ClassLoader類的例項,ClassLoader實際上對應的是類載入器,在Java中主要有一下三種類載入器;
Booststrap ClassLoader:此載入器採用C++編寫,一般開發中是看不到的;
Extendsion ClassLoader:用來進行擴充套件類的載入,一般對應的是jre\lib\ext目錄中的類;
AppClassLoader:(預設)載入classpath指定的類,是最常使用的是一種載入器。
動態代理
與靜態代理類對照的是動態代理類,動態代理類的位元組碼在程式執行時由Java反射機制動態生成,無需程式設計師手工編寫它的原始碼。動態代理類不僅簡化了程式設計工作,而且提高了軟體系統的可擴充套件性,因為Java 反射機制可以生成任意型別的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 介面提供了生成動態代理類的能力。
動態代理示例:
1、BookFacade.java
Java程式碼
- package net.battier.dao;
- public interface BookFacade {
- public void addBook();
- }
2、BookFacadeImpl.java
Java程式碼
- package net.battier.dao.impl;
- import net.battier.dao.BookFacade;
- public class BookFacadeImpl implements BookFacade {
- @Override
- public void addBook() {
- System.out.println("增加圖書方法。。。");
- }
- }
- 、BookFacadeProxy.java
- package net.battier.proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- * JDK動態代理代理類
- *
- * @author student
- *
- */
- public class BookFacadeProxy implements InvocationHandler {
- private Object target;
- /**
- * 繫結委託物件並返回一個代理類
- * @param target
- * @return
- */
- public Object bind(Object target) {
- this.target = target;
- //取得代理物件
- return Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), this); //要繫結介面(這是一個缺陷,cglib彌補了這一缺陷)
- }
- @Override
- /**
- * 呼叫方法
- */
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result=null;
- System.out.println("事物開始");
- //執行方法
- result=method.invoke(target, args);
- System.out.println("事物結束");
- return result;
- }
- }
3、TestProxy.java
Java程式碼
- package net.battier.test;
- import net.battier.dao.BookFacade;
- import net.battier.dao.impl.BookFacadeImpl;
- import net.battier.proxy.BookFacadeProxy;
- public class TestProxy {
- public static void main(String[] args) {
- BookFacadeProxy proxy = new BookFacadeProxy();
- BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
- bookProxy.addBook();
- }
- }
但是,JDK的動態代理依靠介面實現,如果有些類並沒有實現介面,則不能使用JDK代理,這就要使用cglib動態代理了。
Cglib動態代理
JDK的動態代理機制只能代理實現了介面的類,而不能實現介面的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類進行代理。
示例
1、BookFacadeCglib.java
Java程式碼
- package net.battier.dao;
- public interface BookFacade {
- public void addBook();
- }
2、BookCadeImpl1.java
Java程式碼
- package net.battier.dao.impl;
- /**
- * 這個是沒有實現介面的實現類
- *
- * @author student
- *
- */
- public class BookFacadeImpl1 {
- public void addBook() {
- System.out.println("增加圖書的普通方法...");
- }
- }
3、BookFacadeProxy.java
Java程式碼
- package net.battier.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動態代理
- *
- * @author student
- *
- */
- public class BookFacadeCglib implements MethodInterceptor {
- private Object target;
- /**
- * 建立代理物件
- *
- * @param target
- * @return
- */
- public Object getInstance(Object target) {
- this.target = target;
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(this.target.getClass());
- // 回撥方法
- enhancer.setCallback(this);
- // 建立代理物件
- return enhancer.create();
- }
- @Override
- // 回撥方法
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy proxy) throws Throwable {
- System.out.println("事物開始");
- proxy.invokeSuper(obj, args);
- System.out.println("事物結束");
- return null;
- }
- }
4、TestCglib.java
Java程式碼
- package net.battier.test;
- import net.battier.dao.impl.BookFacadeImpl1;
- import net.battier.proxy.BookFacadeCglib;
- public class TestCglib {
- public static void main(String[] args) {
- BookFacadeCglib cglib=new BookFacadeCglib();
- BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
- bookCglib.addBook();
- }
- }
相關文章
- Java代理(jdk靜態代理、動態代理和cglib動態代理)JavaJDKCGLib
- JDK動態代理和CGLib代理JDKCGLib
- JDK動態代理和 CGLIB 代理JDKCGLib
- Java JDK Proxy和CGLib動態代理示例講解JavaJDKCGLib
- spring aop原理 JDK動態代理和CGLIB動態代理SpringJDKCGLib
- 靜態代理和動態代理(jdk/cglib)詳解JDKCGLib
- Java動態代理 jdk和cglib的實現比較JavaJDKCGLib
- 動態代理jdk和cglib的區別JDKCGLib
- 你必須會的 JDK 動態代理和 CGLIB 動態代理JDKCGLib
- Java提高班(六)反射和動態代理(JDK Proxy和Cglib)Java反射JDKCGLib
- JDK 和 CGLib 實現動態代理和區別JDKCGLib
- cglib動態代理和jdk動態代理的區別與應用CGLibJDK
- 代理模式詳解:靜態代理、JDK動態代理與Cglib動態代理模式JDKCGLib
- SpringAOP中JDK和CGLib動態代理哪個更快?SpringJDKCGLib
- 面試造火箭系列,栽在了cglib和jdk動態代理面試CGLibJDK
- 動態代理jdk的Proxy與spring的CGlibJDKSpringCGLib
- Spring原始碼剖析5:JDK和cglib動態代理原理詳解Spring原始碼JDKCGLib
- CGLib 動態代理CGLib
- Jdk代理和CGLIB代理的區別JDKCGLib
- Spring動態代理的生成-如何判斷是使用JDK動態代理還是CGlib代理SpringJDKCGLib
- Jmh測試JDK,CGLIB,JAVASSIST動態代理方式的效能JDKCGLibJava
- 動態代理-cglib分析CGLib
- 3.靜態代理&動態代理&CGlibCGLib
- Java架構-Java JDK 動態代理Java架構JDK
- 《Proxy系列專題》:代理模式(靜態、JDK、CGLib)模式JDKCGLib
- 死磕Spring之AOP篇 - 初識JDK、CGLIB兩種動態代理SpringJDKCGLib
- JDK動態代理JDK
- CGLib動態代理原理及實現CGLib
- 【深度思考】聊聊CGLIB動態代理原理CGLib
- 設計模式之cglib動態代理設計模式CGLib
- JDK動態代理初探JDK
- java基礎:深入理解JDK動態代理JavaJDK
- Java中的靜態代理和動態代理Java
- java 反射和動態代理Java反射
- jdk的動態代理和靜態代理你還寫不出來嘛???JDK
- 深挖JDK動態代理(一)JDK
- JDK動態代理詳解JDK
- 由《尋秦記》說代理模式(靜態,動態,CGLib)模式CGLib