基礎代碼準備java
接口類:程序員
public interface IUser { /** * 判斷用戶的權限 * @param uid 用戶的UID * @return */ public boolean isAuthUser(int uid); }
實現類:框架
/** * 類的實現 * @author Jason * */ public class UserImpl implements IUser { @Override public boolean isAuthUser(int uid) { //作一些權限驗證的工做 System.out.println(uid); //.... return false; } }
靜態代理
ide
由程序員建立或特定工具自動生成源代碼,再對其編譯,在程序運行前,代理類的.class文件就已經存在了。工具
原理:性能
對普通一個接口與一直實現類在加入一個代理類,用於包裝實現類中實現的方法,而業務使用方只須要實例化代理類,並傳遞須要代理的普通類便可。測試
優勢:ui
編譯時生成代碼,性能高this
缺點:代理
一個代理類只能爲一個接口服務,開發中必然會產生過多的代理
全部的代理操做除了調用的方法不同以外,其餘的操做都同樣,則此時確定是重複代碼
代碼示例
代理類
/** * 經過代理類,實現代理接口,經過構造進行實現的代理,在每一個方法裏面進行日誌捕獲 * <pre> * 外部實現權限驗證的時候,只須要之所想該方法便可,不須要再去實現UserImpl方法了 * <pre> */ public class UserProxy implements IUser { private UserImpl userImpl; // 構造的時候直接傳入代理實現類 public UserProxy(UserImpl userImpl) { super(); this.setUserImpl(userImpl); } @Override public boolean isAuthUser(int uid) { System.out.println("proxy insert msg:準備權限驗證,有必要這裏能夠發送消息到MQ,作實時登陸驗證次數預警處理"); boolean b = userImpl.isAuthUser(uid); System.out.println("proxy insert msg:驗證完成,作一些清理等工做....."); return b; } // ***********get,set************ public UserImpl getUserImpl() { return userImpl; } public void setUserImpl(UserImpl userImpl) { this.userImpl = userImpl; } }
public static void main(String[] args) { UserProxy userProxy = new UserProxy(new UserImpl()); userProxy.isAuthUser(5); }
動態代理
原理:
動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。
優勢
能夠經過一個代理類,完成全部代理工做,不須要向靜態代理須要一個一個實現接口來代理
缺點
經過反射動態代理方法將消耗系統性能,若是很是多的話,性能比較低
JDK動態代理
原理:JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理
代理類:UserJDKProxy
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK動態代理代理類,能夠將InvocationHandler接口的子類想象成一個代理的最終操做類 * JDK的動態代理依靠接口實現,若是有些類並無實現接口,則不能使用JDK代理,這個也是缺陷 * @author Jason * */ public class UserJDKProxy implements InvocationHandler { // 須要代理的類 private Object target; public UserJDKProxy() { super(); } /** * 綁定委託對象並返回一個代理類 ClassLoader loader:類加載器 Class<?>[] interfaces:獲得所有的接口 InvocationHandler * h:獲得InvocationHandler接口的子類實例 * * @param target * @return */ public Object initUserJDKProxy(Object target) { this.target = target; // 能夠看出這裏的第二個參數是獲取接口,那麼也就是說咱們實現代理,須要類去實現接口,在有的時候,類是沒有接口的,因此這裏是一個缺陷 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 調用具體的方法 * * @param proxy * 指被代理的對象 * @param method * 要調用的方法 * @param args * 方法調用時所須要的參數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy:這裏攔截處理一下事情....,如監控參數、插入日誌...."); //傳入處理對象和參數 Object object = method.invoke(target, args); System.out.println("proxy:這裏作一些收尾工做...."); return object; } }
測試:
UserJDKProxy userJDKProxy=new UserJDKProxy(); IUser iUser=(IUser) userJDKProxy.initUserJDKProxy(new UserImpl()); iUser.isAuthUser(19);
CGLib動態代理
原理:cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。
這裏須要注意,改包須要引入外部包,提供pom
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
代理類:UserCglibProxy
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 Jason * */ public class UserCglibProxy implements MethodInterceptor { private Object target; public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(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("能夠作一些監控、預警等工做..."); Object object = proxy.invokeSuper(obj, args); System.out.println("收尾工做...."); return object; } }
測試
UserCglibProxy userCglibProxy=new UserCglibProxy(); UserImpl userImpl=(UserImpl) userCglibProxy.getInstance(new UserImpl()); userImpl.isAuthUser(50);
其餘
動態代理在咱們使用的框架Spring中已經運用到,主要是AOP,他主要是動態代理+反射的方式
如Spring經過CGLib來實現了類代理方式,經過Java動態代理來實現接口代理,從而把兩種動態代理結合使用