深刻浅出 cglib,打造无入侵的类代理

cglib 是什么?cglib 是一个强大的,高性能,高质量的代码生成类库。它能够在运行期扩展 Java 类或者实现 Java 接口。固然这些实际的功能是 asm 所提供的,asm 又是什么?它是 Java 字节码操控框架,具体是什么你们能够上网查一查,毕竟咱们这里所要讨论的是 cglib。cglib 就是封装了 asm,简化了 asm 的操做,实现了在运行期动态生成新的 class 的壹个第三方类库。可能你们还感受不到它的强大,如今就告诉你。实际上 cglib 为 spring aop 提供了底层的一种实现;为 hibernate 使用 cglib 动态生成 VO/PO(接口层对象)。  java

下面咱们将经过一个具体的事例来看一下 cglib,体验一下 cglib。使用到的 Jar 包有 cglib-2.13.jar 和 asm-2.23.jar。以壹個实例简单介绍下 cglib 的应用。 spring

咱们模拟一个虚拟的场景,模拟对表的操做。壹开始咱们对表提供了CRUD方法。咱们如今建立一个对 Table 操做的 DAO 类。源代码以下: 框架

public class TableDAO {
	public void create(){
		System.out.println("create() is running !");
	}
	public void query(){
		System.out.println("query() is running !");
	}
	public void update(){
		System.out.println("update() is running !");
	}
	public void delete(){
		System.out.println("delete() is running !");
	}
}
OK,它就是一个 JavaBean,提供了 CRUD 方法的 JavaBean。下面咱们建立一个DAO工厂,用来生成DAO实例。
public class TableDAOFactory {
	private static TableDAO tDao = new TableDAO();
	public static TableDAO getInstance(){
		return tDao;
	}
}
接下来咱们建立客户端,用来调用CRUD方法。
public class Client {

	public static void main(String[] args) {
		TableDAO tableDao = TableDAOFactory.getInstance();
		doMethod(tableDao);
	}
	public static void doMethod(TableDAO dao){
		dao.create();
		dao.query();
		dao.update();
		dao.delete();
	}
}
OK,完成了,CRUD方法彻底被调用了。固然这里并无 cglib 的任何内容。问题不会这么简单的就结束,新的需求来临了。


变化随之而来,Boss告诉咱们这些方法不能开放给用户,只有“张三”才有权使用。怎么办,难道咱们要在每一个方法上面进行判断吗?好像这么作也太那啥了吧,对了对了,Proxy 多是最好的解决办法。jdk 的代理就能够解决了。好了咱们来动手改造吧。等等,jdk 的代理须要实现接口,这样,咱们的dao类须要改变了。既然不想改动dao 又要使用代理,咱们这就请出 cglib。咱们只需新增一个权限验证的方法拦截器。 性能

public class AuthProxy implements MethodInterceptor {
	private String name ;
	//传入用户名称
	public AuthProxy(String name){
		this.name = name;
	}
	public Object intercept(Object arg0, Method arg1, Object[] arg2,
			MethodProxy arg3) throws Throwable {
		//用户进行判断
		if(!"张三".equals(name)){
			System.out.println("你没有权限!");
			return null;
		}
		return arg3.invokeSuper(arg0, arg2);
	}
}
固然不能忘了对咱们的dao工厂进行修改,咱们提供一个使用代理的实例生成方法。
public static TableDAO getAuthInstance(AuthProxy authProxy){
	Enhancer en = new Enhancer();
	//进行代理
	en.setSuperclass(TableDAO.class);
	en.setCallback(authProxy);
	//生成代理实例
	return (TableDAO)en.create();
}
咱们这就能够看看客户端的实现了。添加了两个方法用来验证不一样用户的权限。
public static void haveAuth(){
	TableDAO tDao = TableDAOFactory.getAuthInstance(new AuthProxy("张三"));
	doMethod(tDao);
}
public static void haveNoAuth(){
	TableDAO tDao = TableDAOFactory.getAuthInstance(new AuthProxy("李四"));
	doMethod(tDao);
}
OK,"张三"的正常执行,"李四"的没有执行。
看到了吗?简单的aop就这样实现了
难道就这样结束了么?
3. Boss又来训话了,不行不行,如今除了"张三"其余人都用不了了,如今不能够这样。他们都来向我反映了,必须使用开放查询功能。哈哈,如今可难不倒咱们了,由于咱们使用了CGlib。固然最简单的方式是去修改咱们的方法拦截器,不过这样会使逻辑变得复杂,且不利于维护。还好CGlib给咱们提供了方法过滤器(CallbackFilter),CallbackFilte能够明确代表,被代理的类中不一样的方法,被哪一个拦截器所拦截。下面咱们就来作个过滤器用来过滤query方法。
public class AuthProxyFilter implements CallbackFilter{
	public int accept(Method arg0) {
		if(!"query".equalsIgnoreCase(arg0.getName()))
			return 0;
		return 1;
	}

}
OK,可能你们会对返回值 0 或者 1 感到困惑,用到的时候就会讲解,固然下面就会用到了。

咱们在工厂中新增一个使用了过滤器的实例生成方法。 this

public static TableDAO getAuthInstanceByFilter(AuthProxy authProxy){
	Enhancer en = new Enhancer();
	en.setSuperclass(TableDAO.class);
	en.setCallbacks(new Callback[]{authProxy,NoOp.INSTANCE});
	en.setCallbackFilter(new AuthProxyFilter());
	return (TableDAO)en.create();
}

看到了吗,setCallbacks() 中定义了所使用的拦截器,其中 NoOp.INSTANCE 是 CGlib 所提供的实际是一个没有任何操做的拦截器,他们是有序的。必定要和 CallbackFilter 里面的顺序一致。明白了吗?上面return返回的就是返回的顺序。也就是说若是调用 query 方法就使用 NoOp.INSTANCE 进行拦截。
如今看一下客户端代码。
spa

public static void haveAuthByFilter(){
	TableDAO tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("张三"));
	doMethod(tDao);

	tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("李四"));
	doMethod(tDao);
}

OK,如今"李四"也可使用query方法了,其余方法仍然没有权限。固然这个代理的实现没有任何侵入性,无需强制让 dao 去实现接口。
hibernate

相关文章
相关标签/搜索