深刻探索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动态代理.

相关文章
相关标签/搜索