靜態代理與動態代理實現與原理

基礎代碼準備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

缺點:代理

  1. 一個代理類只能爲一個接口服務,開發中必然會產生過多的代理

  2. 全部的代理操做除了調用的方法不同以外,其餘的操做都同樣,則此時確定是重複代碼

代碼示例

代理類

/**
 * 經過代理類,實現代理接口,經過構造進行實現的代理,在每一個方法裏面進行日誌捕獲
 * <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動態代理來實現接口代理,從而把兩種動態代理結合使用

相關文章
相關標籤/搜索