深入浅出CGlib——打造无入侵的类代理

原文链接

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

下面我们将通过一个具体的事例来看一下CGlib体验一下CGlib。
* CGlib 2.13
* ASM 2.23
以一个实例在简单介绍下cglib的应用。
我们模拟一个虚拟的场景,模拟对表的操作。
1. 开始我们对表提供了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的任何内容。问题不会这么简单的就结束,新的需求来临了。
2. 变化随之而来,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,可能大家会对return 0 or 1感到困惑,用到的时候就会讲解,当然下面就会用到了。
我们在工场中新增一个使用了过滤器的实例生成方法。

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进行拦截。
现在看一下客户端代码。

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

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

ok,现在”李四”也可以使用query方法了,其他方法仍然没有权限。
哈哈,当然这个代理的实现没有任何侵入性,无需强制让dao去实现接口。
如果大家对java的深入研究有兴趣
可以加入Q群:46176507 共同进步学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值