代理模式是常用的java設計模式,他的特征是代理類與委托類有同樣的介面,代理類主要負責為委托類預處理訊息、過濾訊息、把訊息轉發給委托類,以及事后處理訊息等,代理類與委托類之間通常會存在關聯關系,一個代理類的物件與一個委托類的物件關聯,代理類的物件本身并不真正實作服務,而是通過呼叫委托類的物件的相關方法,來提供特定的服務, 按照代理的創建時期,代理類可以分為兩種, 靜態代理:由程式員創建或特定工具自動生成源代碼,再對其編譯,在程式運行前,代理類的.class檔案就已經存在了, 動態代理:在程式運行時,運用反射機制動態創建而成,
靜態代理
1、Count.java package net.battier.dao; /** * 定義一個賬戶介面 * * @author Administrator * */ public interface Count { // 查看賬戶方法 public void queryCount(); // 修改賬戶方法 public void updateCount(); } 2、CountImpl.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("修改賬戶方法..."); } } 3、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 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動態代理
jdk動態代理中包含一個類和一個介面: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介面的子類實體 類加載器 在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 package net.battier.dao; public interface BookFacade { public void addBook(); } 2、BookFacadeImpl.java package net.battier.dao.impl; import net.battier.dao.BookFacade; public class BookFacadeImpl implements BookFacade { @Override public void addBook() { System.out.println("我是方法,我在處理事情,,,"); } } 3、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 FacadeProxy 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; } } 4、TestProxy.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) { FacadeProxy proxy = new FacadeProxy(); BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); bookProxy.addBook(); } } 執行結果:被代理方法執行前做點事,,,我是方法,我在處理事情,,,被代理方法執行后做點事,,,和靜態代理類相比的優勢時只需要定義一個 FacadeProxy代理類即可代理各種不同的類;比如現在要再代理一個CarFacadeImpl類,只需要執行BookFacade carProxy = (CarFacade) proxy.bind(new CarFacadeImpl())而不要再new一個新的FacadeProxy代理類;所以叫作動態代理,但是,JDK的動態代理依靠介面實作,如果有些類并沒有實作介面,則不能使用JDK代理,這就要使用cglib動態代理了,
Cglib動態代理
JDK的動態代理機制只能代理實作了介面的類,而不能實作介面的類就不能實作JDK的動態代理1、cglib是針對類來實作代理的,他的原理是對指定的目標類生成一個子類,并覆寫其中方法實作增強;2、但因為采用的是繼承,所以不能對final修飾的類進行代理, 示例1、BookFacadeCglib.java package net.battier.dao; public interface BookFacade { public void addBook(); } 2、BookCadeImpl1.java package net.battier.dao.impl; /** * 這個是沒有實作介面的實作類 * * @author student * */ public class BookFacadeImpl1 { public void addBook() { System.out.println("增加圖書的普通方法..."); } } 3、BookFacadeProxy.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 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(); } } 本文轉自:https://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/32482.html
標籤:設計模式
