代理模式-CGLIB動態代理

1.JDK動態代理是實現了被代理對象的接口,Cglib是繼承了被代理對象。
2.JDK和Cglib都是在運行期生成字節碼,JDK是直接寫Class字節碼,Cglib使用ASM框架寫Class字節碼,Cglib代理實現更復雜,生成代理類比JDK效率低。
3.JDK調用代理方法,是通過反射機制調用,Cglib是通過FastClass機制直接調用方法。

CGLIB動態代理

使用JDK的Proxy實現代理,要求目標類與代理類實現相同的接口。若目標類不存在接口,則無法使用該方式實現。

但對於無接口的類,要爲其創建動態代理類,就要使用CGLIB來實現。CGLIB代理的生成原理是生成目標類的子類,而子類是增強過的,這個子類對象就是代理對象。所以,使用CGLIB生成動態代理,要求目標類必須能夠被繼承,即不能是final的類。

CGLIB(Code Generation Library)是一個開源項目,是一個強大的、高性能的、高質量的代碼生成類庫。它可以在運行期擴展喝增強Java類。Hibernate用它來實現持久對象的字節碼的動態生成,Spring用它來實現AOP編程。

CGLIB包的底層是通過使用一個小而快的字節碼處理框架ASM(Java字節碼操控框架)來轉換字節碼並生成新的類。CGLIB是通過對字節碼進行增強來生成代理的。

代理實現與解析:

使用CGLIB創建代理步驟:

步驟1:導入CGLIB的Jar包:cglib-full.jar。

步驟2:定義目標類。注意不用實現任何接口。

public class AccountService {
	//目標方法
	public void transfer(){
		System.out.println("調用Dao層,完成轉賬主業務。");
	}
	//目標方法
	public void getBalance(){
		System.out.println("調用Dao層,完成查詢餘額主業務。");
	}
	
	//該方法不能被子類覆蓋,Cglib是無法代理final修飾的方法的
	final public void others() {
		System.out.println("調用Dao層,完成其它主業務。");
	}
	
}

步驟3:創建代理類的工廠。該類要實現MethodInterceptor接口。

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

//自定義MethodInterceptor
public class CglibProxyDemo implements MethodInterceptor {
    /*
     * All generated proxied methods call this method instead of the original method. The original method may either be invoked by normal reflection using the Method object, or by using the MethodProxy (faster).     
     * @param obj "this", the enhanced object     
     * @param method intercepted Method     * @param args argument array; primitive types are wrapped     
     * @param proxy used to invoke super (non-intercepted method); may be called as many times as needed     
     * @throws Throwable any exception may be thrown; if so, super method will not be invoked     
     * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.     
     * @see MethodProxy
     * 
     * intercept()方法中各參數的意義
     * proxy:代理對象;表示增強的對象,即實現這個接口類的一個對象,cglib生成的代理對象;
     * method:被代理對象的方法
     * args[]:方法參數;攔截方法的參數
     * methodProxy:代理對象方法的代理對象
     * */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		
		System.out.println("=========進入CGLIB代理=========");
		
		Object result = null;
		// 若爲transfer方法,則進行增強
		if("transfer".equals(method.getName())){
			System.out.println("===前置處理時間:" + System.currentTimeMillis());
			result = methodProxy.invokeSuper(proxy, args);
			System.out.println("===後置處理時間:" + System.currentTimeMillis());
			return result;
		}
		return methodProxy.invokeSuper(proxy, args);
	}
}

步驟4:創建測試類。

import net.sf.cglib.core.DebuggingClassWriter;
import java.io.IOException;
import net.sf.cglib.proxy.Enhancer;
import com.proxyDemo.cglibProxy.service.TargetService;
import com.proxyDemo.cglibProxy.service.CglibProxyDemo;

public class CglibMainDemo {
	public static void main(String[] args) throws IOException {
		// 代理類class文件存入本地磁盤方便我們反編譯查看源碼
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
		
		//創建增強器
    	Enhancer enhancer = new Enhancer();
    	//初始化增強器:將目標類指定爲父類
    	enhancer.setSuperclass(new TargetService().getClass());
    	//初始化增強器:設置回調
    	enhancer.setCallback(new CglibProxyDemo());
    	//通過Enhancer.create()方法創建代理對象
    	TargetService service = (TargetService) enhancer.create();
    	//通過代理對象調用目標方法
    	service.transfer();
    	service.getBalance();
		service.others();
	}
}

查看生成代理對象反編譯後代碼如下:

import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TargetService$$EnhancerByCGLIB$$bde35d74 extends TargetService
  implements Factory
{
  private boolean CGLIB$BOUND;
  private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
  private static Callback[] CGLIB$DEFAULT_CALLBACKS;
  private MethodInterceptor CGLIB$CALLBACK_0;
  private static final Method CGLIB$transfer$0$0$Method;
  private static final MethodProxy CGLIB$transfer$0$0$Proxy;
  private static final Object[] CGLIB$emptyArgs;
  private static final Method CGLIB$getBalance$0$1$Method;
  private static final MethodProxy CGLIB$getBalance$0$1$Proxy;
  private static final Method CGLIB$finalize$0$2$Method;
  private static final MethodProxy CGLIB$finalize$0$2$Proxy;
  private static final Method CGLIB$equals$0$3$Method;
  private static final MethodProxy CGLIB$equals$0$3$Proxy;
  private static final Method CGLIB$toString$0$4$Method;
  private static final MethodProxy CGLIB$toString$0$4$Proxy;
  private static final Method CGLIB$hashCode$0$5$Method;
  private static final MethodProxy CGLIB$hashCode$0$5$Proxy;
  private static final Method CGLIB$clone$0$6$Method;
  private static final MethodProxy CGLIB$clone$0$6$Proxy;

  static void CGLIB$STATICHOOK1()
  {
    CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    Class localClass;
    CGLIB$emptyArgs = new Object[0];
    ClassLoader tmp27_17 = (localClass = Class.forName("com.proxyDemo.cglibProxy.service.TargetService$$EnhancerByCGLIB$$bde35d74")).getClassLoader();
    CGLIB$transfer$0$0$Proxy = MethodProxy.create(tmp27_17, (bde35d74.CGLIB$transfer$0$0$Method = Class.forName("com.proxyDemo.cglibProxy.service.TargetService").getDeclaredMethod("transfer", new Class[0])).getDeclaringClass(), localClass, "()V", "transfer", "CGLIB$transfer$0$0");
    ClassLoader tmp62_27 = tmp27_17;
    CGLIB$getBalance$0$1$Proxy = MethodProxy.create(tmp62_27, (bde35d74.CGLIB$getBalance$0$1$Method = Class.forName("com.proxyDemo.cglibProxy.service.TargetService").getDeclaredMethod("getBalance", new Class[0])).getDeclaringClass(), localClass, "()V", "getBalance", "CGLIB$getBalance$0$1");
    ClassLoader tmp97_62 = tmp62_27;
    CGLIB$finalize$0$2$Proxy = MethodProxy.create(tmp97_62, (bde35d74.CGLIB$finalize$0$2$Method = Class.forName("java.lang.Object").getDeclaredMethod("finalize", new Class[0])).getDeclaringClass(), localClass, "()V", "finalize", "CGLIB$finalize$0$2");
    ClassLoader tmp132_97 = tmp97_62;
    CGLIB$equals$0$3$Proxy = MethodProxy.create(tmp132_97, (bde35d74.CGLIB$equals$0$3$Method = Class.forName("java.lang.Object").getDeclaredMethod("equals", new Class[] { Class.forName("java.lang.Object") })).getDeclaringClass(), localClass, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$0$3");
    ClassLoader tmp175_132 = tmp132_97;
    CGLIB$toString$0$4$Proxy = MethodProxy.create(tmp175_132, (bde35d74.CGLIB$toString$0$4$Method = Class.forName("java.lang.Object").getDeclaredMethod("toString", new Class[0])).getDeclaringClass(), localClass, "()Ljava/lang/String;", "toString", "CGLIB$toString$0$4");
    ClassLoader tmp210_175 = tmp175_132;
    CGLIB$hashCode$0$5$Proxy = MethodProxy.create(tmp210_175, (bde35d74.CGLIB$hashCode$0$5$Method = Class.forName("java.lang.Object").getDeclaredMethod("hashCode", new Class[0])).getDeclaringClass(), localClass, "()I", "hashCode", "CGLIB$hashCode$0$5");
    CGLIB$clone$0$6$Proxy = MethodProxy.create(tmp210_175, (bde35d74.CGLIB$clone$0$6$Method = Class.forName("java.lang.Object").getDeclaredMethod("clone", new Class[0])).getDeclaringClass(), localClass, "()Ljava/lang/Object;", "clone", "CGLIB$clone$0$6");
    return;
  }

  final void CGLIB$transfer$0$0()
  {
    super.transfer();
  }

  public final void transfer()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null)
      return;
    super.transfer();
  }
      ......
  public final void getBalance()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null)
      return;
    super.getBalance();
  }
      ......
      ......
  static
  {
    CGLIB$STATICHOOK1();
  }
}

從代理對象反編譯源碼可以知道,代理對象繼承於TargetService

希望對你有幫助,祝你有一個好心情,加油!

若有錯誤、不全、可優化的點,歡迎糾正與補充!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章