1. 程式人生 > >淺談java中的cglib代理

淺談java中的cglib代理

什麼是cglib代理?

    定義:cglib代理,也叫做子類代理。在記憶體中構建一個子類物件從而實現對目標物件功能的擴充套件。

上一篇部落格

物件必須實現至少一個介面。那麼如果被代理的物件想要拓展功能,但又沒有實現介面,該怎麼辦呢?

我們就可以使用cglib代理來解決了。

CGLIB是一個強大的高效能的程式碼生成包,它可以在執行期擴充套件Java類與實現Java介面。它廣泛的被許多AOP的框架

使用,例如Spring AOPdynaop,為他們提供方法的interception(攔截)。

CGLIB包的底層是通過使用一個小而快的位元組碼處理框架ASM,來轉換位元組碼並生成新的類。不鼓勵直接使用ASM

因為它要求你必須對JVM內部結構包括class檔案的格式和指令集都很熟悉。

Cglib子類代理:

1) 需要引入cglib – jar檔案, 但是spring的核心包中已經包括了cglib功能,我這裡引入spring-core-3.2.5.jar

2)引入功能包後,就可以在記憶體中動態構建子類

3)代理的類不能為final, 否則報錯。

4) 目標物件的方法如果為final/static, 那麼就不會被攔截,即不會執行目標物件額外的業務方法。

下面我們通過程式碼來說明一下

首先建立一個UserDao類,類裡面有save和update兩個方法

public class UserDao {

	public void save(){
		System.out.println("資料已經儲存");
	}
	
	public void update(){
		System.out.println("資料已經更新");
	}
}

再建立一個CglibProxyFactory類,實現org.springframework.cglib.proxy.MethodProxy介面

CglibProxyFactory類中需要通過Enhancer類建立子類代理物件

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * cglib子類代理工廠 對UserDao在記憶體中動態構建一個子類物件
 * 
 * @author wangchaoyouziying
 *
 */
public class CglibProxyFactory implements MethodInterceptor {

	private Object target;// 被代理物件

	public CglibProxyFactory(Object target) {
		this.target = target;
	}

	/**
	 * 建立代理物件
	 * 
	 * @return
	 */
	public Object getProxyInstance() {
		Enhancer enhancer = new Enhancer();
		// 設定父類
		enhancer.setSuperclass(target.getClass());
		// 設定回撥函式
		enhancer.setCallback(this);
		// 建立子類(代理物件)
		return enhancer.create();
	}

	/**
	 * obj		代理物件
	 * method	被代理物件的方法
	 * args		被代理物件的引數
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		if ("save".equals(method.getName())) {//這裡只改造被代理物件的save方法
			System.out.println("開始事務");
			// 執行被代理物件的方法
			Object invoke = method.invoke(target, args);
			System.out.println("提交事務");
			return invoke;
		}else{//其餘方法按原樣執行
			return method.invoke(target, args);
		}
	}

}

測試一下

public class Test {

	public static void main(String[] args) {
		//被代理物件
		UserDao userDao = new UserDao();
		//class cn.chao.cglibProxy.UserDao
		System.out.println(userDao.getClass());
		//代理物件
		UserDao proxy = (UserDao) new CglibProxyFactory(userDao).getProxyInstance();
		//UserDao的子類	class cn.chao.cglibProxy.UserDao$$EnhancerByCGLIB$$e6c21b2c
		System.out.println(proxy.getClass());
		//執行代理物件的方法
		proxy.save();
		proxy.update();
	}

}

執行結果:

class cn.chao.cglibProxy.UserDao
class cn.chao.cglibProxy.UserDao$$EnhancerByCGLIB$$e6c21b2c
開始事務
資料已經儲存
提交事務
資料已經更新