`
anson_xu
  • 浏览: 502299 次
  • 性别: Icon_minigender_1
  • 来自: 惠州
社区版块
存档分类

CGlib简单介绍

阅读更多
05-11 (转)CGlib简单介绍
原文:http://www.blogjava.net/stone2083/archive/2008/03/16/186615.html

CGlib概述:

cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

cglib封装了asm,可以在运行期动态生成新的class。

cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。

CGlib应用:

以一个实例在简单介绍下cglib的应用。

我们模拟一个虚拟的场景,关于信息的管理。

1)原始需求是任何人可以操作信息的create,update,delete,query操作。

InfoManager.java--封装对信息的操作

public class InfoManager {

    // 模拟查询操作

    public void query() {

         System.out.println("query");

     }

    // 模拟创建操作

    public void create() {

         System.out.println("create");

     }

    // 模拟更新操作

    public void update() {

         System.out.println("update");

     }

    // 模拟删除操作

    public void delete() {

         System.out.println("delete");

     }

}

InfoManagerFactory.java--工厂类

public class InfoManagerFactory {

    private static InfoManager manger = new InfoManager();

    /**

      * 创建原始的InfoManager

      *

      * @return

     */

    public static InfoManager getInstance() {

        return manger;

     }

}

client.java--供客户端调用

public class Client {

    public static void main(String[] args) {

         Client c = new Client();

         c.anyonecanManager();

     }

    /**

      * 模拟:没有任何权限要求,任何人都可以操作

     */

    public void anyonecanManager() {

         System.out.println("any one can do manager");

         InfoManager manager = InfoManagerFactory.getInstance();

         doCRUD(manager);

         separatorLine();

     }

    /**

      * 对Info做增加/更新/删除/查询操作

      *

      * @param manager

     */

    private void doCRUD(InfoManager manager) {

         manager.create();

         manager.update();

         manager.delete();

         manager.query();

     }

    /**

      * 加一个分隔行,用于区分

     */

    private void separatorLine() {

         System.out.println("################################");

     }

}

至此,没有涉及到cglib的内容,因为需求太简单了,但是接下来,需求发生了改变,要求:

2)只有一个叫“maurice”的用户登录,才允许对信息进行create,update,delete,query的操作。

怎么办?难道在每个方法前,都加上一个权限判断吗?这样重复逻辑太多了,于是乎想到了Proxy(代理模式),但是原先的InfoManager也没有实现接口,不能采用jdk的proxy。那么cglib在这边就要隆重登场。

一旦使用cgblig,只需要添加一个MethodInterceptor的类以及修改factory代码就可以实现这个需求。

AuthProxy.java--权限校验代理类

public class AuthProxy implements MethodInterceptor {

    private String name; // 会员登录名

    public AuthProxy(String name) {

        this.name = name;

     }

    /**

      * 权限校验,如果会员名为:maurice,则有权限做操作,否则提示没有权限

     */

     @Override

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

        if (!"maurice".equals(this.name)) {

             System.out.println("AuthProxy:you have no permits to do manager!");

            return null;

         }

        return proxy.invokeSuper(obj, args);

     }

    public String getName() {

        return name;

     }

    public void setName(String name) {

        this.name = name;

     }

}

InfoManagerFactory.java--代码变动如下:

public class InfoManagerFactory {

    /**

      * 创建带有权限检验的InfoManager

      *

      * @param auth

      * @return

     */

    public static InfoManager getAuthInstance(AuthProxy auth) {

         Enhancer enhancer = new Enhancer();

         enhancer.setSuperclass(InfoManager.class);

         enhancer.setCallback(auth);

        return (InfoManager) enhancer.create();

     }

   

}

client.java--代码修改如下

public class Client {

    public static void main(String[] args) {

         Client c = new Client();

         c.haveNoAuthManager();

         c.haveAuthManager();

     }

    /**

      * 模拟:登录会员没有权限

     */

    public void haveNoAuthManager() {

         System.out.println("the loginer's name is not maurice,so have no permits do manager");

         InfoManager noAuthManager = InfoManagerFactory.getAuthInstance(new AuthProxy("maurice1"));

         doCRUD(noAuthManager);

         separatorLine();

     }

    /**

      * 模拟:登录会员有权限

     */

    public void haveAuthManager() {

         System.out.println("the loginer's name is maurice,so have permits do manager");

         InfoManager authManager = InfoManagerFactory.getAuthInstance(new AuthProxy("maurice"));

         doCRUD(authManager);

         separatorLine();

     }

    /**

      * 对Info做增加/更新/删除/查询操作

      *

      * @param manager

     */

    private void doCRUD(InfoManager manager) {

         manager.create();

         manager.update();

         manager.delete();

         manager.query();

     }

    /**

      * 加一个分隔行,用于区分

     */

    private void separatorLine() {

         System.out.println("################################");

     }

}

执行下代码,发现这时client端中已经加上了权限校验。

同样是InfoManager,为什么这时能多了权限的判断呢?Factory中enhancer.create()返回的到底是什么对象呢?这个疑问将在第三部分CGlib中解释。

这边的代码,其实是介绍了cglib中的enhancer功能.

到这里,参照上面的代码,就可以使用cglib带来的aop功能了。但是为了更多介绍下cglib的功能,模拟需求再次发生变化:

3)由于query功能用户maurice才能使用,招来其他用户的强烈的抱怨,所以权限再次变更,只有create,update,delete,才需要权限保护,query任何人都可以使用。

怎么办?采用AuthProxy,使得InfoManager中的所有方法都被代理,加上了权限的判断。当然,最容易想到的办法,就是在 AuthProxy的intercept的方法中再做下判断,如果代理的method是query,不需要权限验证。这么做,可以,但是一旦逻辑比较复杂 的时候,intercept这个方法要做的事情会很多,逻辑会异常的复杂。

幸好,cglib还提供了CallbackFilter。使用CallbackFilter,可以明确表明,被代理的类(InfoManager)中不同的方法,被哪个拦截器(interceptor)拦截。

AuthProxyFilter.java

public class AuthProxyFilter implements CallbackFilter {

    private static final int AUTH_NEED     = 0;

    private static final int AUTH_NOT_NEED = 1;

    /**

      * <pre>

      * 选择使用的proxy

      * 如果调用query函数,则使用第二个proxy

      * 否则,使用第一个proxy

      * </pre>

     */

     @Override

    public int accept(Method method) {

        if ("query".equals(method.getName())) {

            return AUTH_NOT_NEED;

         }

        return AUTH_NEED;

     }

}

这段代码什么意思?其中的accept方法的意思是说,如果代理的方法是query(),那么使用第二个拦截器去拦截,如果代理的方法不是query (),那么使用第一个拦截器去拦截。所以我们只要再写一个拦截器,不做权限校验就行了。(其实,cglib中的NoOp.INSTANCE就是一个空的拦 截器,只要配置上这个就可以了。)

InfoManagerFactory.java--代码修改如下:(配置不同的拦截器和filter)

public class InfoManagerFactory {

    /**

      * 创建不同权限要求的InfoManager

      *

      * @param auth

      * @return

     */

    public static InfoManager getSelectivityAuthInstance(AuthProxy auth) {

         Enhancer enhancer = new Enhancer();

         enhancer.setSuperclass(InfoManager.class);

         enhancer.setCallbacks(new Callback[] { auth, NoOp.INSTANCE });

         enhancer.setCallbackFilter(new AuthProxyFilter());

        return (InfoManager) enhancer.create();

     }

}

记住:setCallbacks中的拦截器(interceptor)的顺序,一定要和CallbackFilter里面指定的顺序一致!!切忌。

Client.java

public class Client {

    public static void main(String[] args) {

         Client c = new Client();

         c.selectivityAuthManager();

     }

   

    /**

      * 模拟:没有权限的会员,可以作查询操作

     */

    public void selectivityAuthManager() {

         System.out.println("the loginer's name is not maurice,so have no permits do manager except do query operator");

         InfoManager authManager = InfoManagerFactory.getSelectivityAuthInstance(new AuthProxy("maurice1"));

         doCRUD(authManager);

         separatorLine();

     }

    /**

      * 对Info做增加/更新/删除/查询操作

      *

      * @param manager

     */

    private void doCRUD(InfoManager manager) {

         manager.create();

         manager.update();

         manager.delete();

         manager.query();

     }

    /**

      * 加一个分隔行,用于区分

     */

    private void separatorLine() {

         System.out.println("################################");

     }

}

此时,对于query的权限校验已经被去掉了。

通过一个模拟需求,简单介绍了cglib aop功能的使用。

CGlib应用非常广,在spring,hibernate等框架中,被大量的使用。

CGlib原理:

cglib神奇吗?其实一旦了解cglib enhancer的原理,一切就真相大白了。

刚才在第二部分中,有个疑问:enhancer.create()到底返回了什么对象?

其实在刚才的例子中,cglib在代码运行期,动态生成了InfoManager的子类,并且根据CallbackFilter的accept方法,覆写了InfoManager中的所有方法--去执行相应的MethodInterceptor的intercept方法

分享到:
评论

相关推荐

    Spring AOP源码分析.mmap

    有关于Spring,我们最常用的两个功能就是IOC和AOP,前几篇文章从源码级别介绍了Spring容器如何为我们生成bean及bean之间的依赖关系 下面我们接着来看AOP的源码实现。 有关于AOP,我们在面试中也被无数次问到...

    JavaEE技术问题汇总.docx

    OSI模型:七层模型介绍 wait方法和Sleep方法简单对比描述一下 comparable与comparator的区别 GC垃圾回收机机制? Java序列化与反序列化是什么?如何实现Java序列化与反序列化.序列化和反序列化使用的API ...

    蚂蚁云客服机器人面试答案.docx

    1、自我介绍、自己做的项目和技术领域 开放题 2、项目中的监控:那个监控指标常见的有哪些? 答:CPU、内存、IO 等等。建议下载个nmon工具,里面有各个指标。 数据库:Mysql(缓存命中、索引、单条SQL性能、数据库...

    《MyEclipse 6 Java 开发中文教程》前10章

    第一章 安装配置开发环境 18 1.1系统需求 18 1.2 JDK 的下载,安装和配置(可...10.7.2 MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 - 用 CGLIB 来实现事务管理 258 10.7.3 Spring相关的参考资料 261

    Spring.3.x企业应用开发实战(完整版).part2

    6.2.3 CGLib动态代理 6.2.4 AOP联盟 6.2.5 代理知识小结 6.3 创建增强类 6.3.1 增强类型 6.3.2 前置增强 6.3.3 后置增强 6.3.4 环绕增强 6.3.5 异常抛出增强 6.3.6 引介增强 6.4 创建切面 6.4.1 切点类型 6.4.2 切面...

    Spring3.x企业应用开发实战(完整版) part1

    6.2.3 CGLib动态代理 6.2.4 AOP联盟 6.2.5 代理知识小结 6.3 创建增强类 6.3.1 增强类型 6.3.2 前置增强 6.3.3 后置增强 6.3.4 环绕增强 6.3.5 异常抛出增强 6.3.6 引介增强 6.4 创建切面 6.4.1 切点类型 6.4.2 切面...

    Spring 2.0 开发参考手册

    7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”advisor 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动...

    spring chm文档

    7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”advisor 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动...

    Spring-Reference_zh_CN(Spring中文参考手册)

    7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”advisor 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动代理...

    Spring中文帮助文档

    7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”通知器 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动...

    Spring API

    7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”通知器 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动...

Global site tag (gtag.js) - Google Analytics