深刻探索spring技術內幕(六): JDK動態代理和cglib生成代理

[ JDK生成代理 ]java

JDK中給咱們提供了一個Proxy類能夠動態的給咱們生成代理.node

假定咱們要作一個權限管理系統, 須要控制用戶對某一個方法的訪問. 若是user爲null, 那麼不讓用戶訪問save方法.框架

① 接口類: PersonService函數

public interface PersonService {
	public void save();
}

② 實現類: PersonServiceImpl測試

public class PersonServiceImpl implements PersonService {
	private String user;
	
	public PersonServiceImpl(){
	}
	
	public PersonServiceImpl(String user) {
		this.user = user;
	}

	public void save() {
		System.out.println("執行了save()方法");
	}

	public String getUser() {
		return user;
	}
}

③ 生成代理類工廠: JDKProxyFactorythis

public class JDKProxyFactory implements InvocationHandler {
	private Object targetObject; //代理的目標對象

	public Object createProxyIntance(Object targetObject) {
		this.targetObject = targetObject;
	    /**
		 * 第一個參數設置代碼使用的類裝載器,通常採用跟目標類相同的類裝載器
		 * 第二個參數設置代理類實現的接口
		 * 第三個參數設置回調對象,當代理對象的方法被調用時,會委派給該參數指定對象的invoke方法
		 */
		return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), 
									  this.targetObject.getClass().getInterfaces(), 
									  this);
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		PersonServiceImpl ps = (PersonServiceImpl) this.targetObject;
		Object result = null;
		if (ps.getUser() != null) { // 若是user爲null, 則沒法調用目標方法
			result = method.invoke(targetObject, args); // 把方法調用委派給目標對象
		}
		return result;
	}
}

④ 測試一把:代理

public class PersonServiceImplTest {
	@Test
	public void testJDKProxy() {
		JDKProxyFactory factory = new JDKProxyFactory();
		PersonService personService = (PersonService) factory.createProxyIntance(new PersonServiceImpl("zhangsan"));
		personService.save();
	}
}

[ CGLIB生成代理 ]code

Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類。對象

使用CGLIB生成代理須要引入cglib-nodep-2.1_3.jar繼承

① CBLIG生成代理工廠: CGlibProxyFactory

public class CGlibProxyFactory implements MethodInterceptor {
	private Object targetObject;

	public Object createProxyIntance(Object targetObject) {
		this.targetObject = targetObject;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.targetObject.getClass()); // 設置代理類的父類
		enhancer.setCallback(this); // 設置回調函數
		return enhancer.create();
	}

	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		PersonServiceImpl bean = (PersonServiceImpl) this.targetObject;
		Object result = null;
		if (bean.getUser() != null) { // 若是user爲null, 則沒法調用目標方法
			result = methodProxy.invoke(targetObject, args);
		}
		return result;
	}
}

② 測試一把

public class PersonServiceImplTest {
	@Test
	public void testCGLIBProxy() {
		CGlibProxyFactory factory = new CGlibProxyFactory();
		PersonService personService = (PersonServiceImpl) factory.createProxyIntance(new PersonServiceImpl("lisi"));
		personService.save();
	}
}

[ 比較兩種代理 ]

1. 使用JDK的動態代理, 被代理類必定要實現了某個接口, 而使用CGLIB, 被代理類沒有實現任何接口也能夠實現動態代理功能, 

2. 由於採用的是繼承, 因此cglib沒法對使用final修飾的類使用代理.

3. CGLIB的速度要遠遠快於JDK Proxy動態代理.

相關文章
相關標籤/搜索