`
pph007
  • 浏览: 11571 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

CGlib动态代理-简单介绍

阅读更多
CGlib简单介绍
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-cglib-repack-3.2.5.jar,spring-objenesis-repack-2.6.jar

    标题中的"spring-cglib-repack-3.2.5.jar"和"spring-objenesis-repack-2.6.jar"是Spring框架在运行时依赖的两个关键库,它们主要涉及到动态代理和对象创建的优化。 1. **CGLIB(Code Generation Library)**: ...

    spring-cglib-repack-3.2.5.jar spring-objenesis-repack-2.6.jar spring依赖包

    当Spring的AOP代理无法通过简单地继承来实现时(例如,目标类为final或包含final方法),CGlib就会介入,通过字节码技术生成目标类的一个子类,以此来实现对目标方法的拦截和增强。CGlib的核心是ASM库,ASM是一个...

    代理模式-静态动态代理-jdk动态代理-cglib动态代理

    在Java中,我们可以使用两种方式实现动态代理:JDK动态代理和CGLIB动态代理。 1. **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。Java的`java.lang.reflect.Proxy`类和...

    cglib动态代理介绍

    下面是一个简单的CGlib动态代理的示例: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;...

    浅谈JDK动态代理与CGLIB代理去区别

    在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...

    jdk与cglib动态代理与底层实现

    - **CGLIB代理**:CGLIB通过ASM生成一个继承自目标类的新类,这个新类覆盖了目标类的所有方法,并在这些方法内部调用拦截器链。在运行时,这个新类的实例作为代理对象。 5. **优缺点**: - JDK代理简单易用,但...

    Spring源码导入Eclipse缺失Jar包spring-asm-repack-5.0.4+spring-cglib-repack-3.1

    Spring在没有指定接口的情况下使用CGLIB来创建代理对象,主要用于AOP代理和动态数据访问对象(DAO)。CGLIB-repack版本也是为了避免与项目中已有的CGLIB版本冲突。 当Spring源码导入Eclipse时,若缺少了这些库,...

    spring-cglib-repack-3.2.6.jar,spring-objenesis-repack-2.6.jar

    在Spring框架中,CGLIB被用作动态代理机制的一部分,特别是在没有接口的情况下,Spring会使用CGLIB来创建目标对象的代理,以便进行AOP(面向切面编程)的拦截处理。CGLIB通过字节码技术生成子类,从而对目标类的方法...

    JDK动态代理和CGLIB代理

    JDK动态代理和CGLIB代理是两种常用的实现方式。 首先,我们来看看JDK动态代理。JDK动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象...

    静态代理、jdk动态代理、cglib动态代理

    Cglib 动态代理的实现方式是:我们首先需要定义一个类,然后使用 Cglib 库来生成该类的代理对象,该代理对象将拦截对被代理对象的所有方法调用,并控制对被代理对象的访问。 Cglib 动态代理的优点是:它的实现方式...

    java代理机制 JDK动态代理和cglib代理 详解

    本文将深入探讨两种主要的Java代理实现:JDK动态代理和CGLIB代理。 一、JDK动态代理 JDK动态代理基于接口实现,它要求被代理的类必须实现至少一个接口。在运行时,Java会动态地创建一个新的类,这个类实现了与原始...

    java动态代理和cglib动态代理示例分享共5页.pdf

    以下是一个简单的CGLIB代理示例: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; ...

    jdk动态代理 cglib3.0动态代理

    JDK动态代理简单易用,但仅限于代理实现接口的类。如果需要代理的类没有实现任何接口,或者需要更细粒度的控制,比如修改方法体,就需要使用CGLIB。CGLIB虽然更强大,但在性能上略逊色于JDK动态代理,因为它涉及到...

    CGlib动态代理的好例子!

    下面是一个简单的CGlib动态代理的例子: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;...

    JAVA动态代理实现Demo(JDK动态代理和CGLIB动态代理)

    Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和...

    cglib动态代理jar包

    总结来说,CGLIB是一个强大的字节码生成库,它使得在Java中实现动态代理变得简单而高效。通过深入理解CGLIB的工作机制和使用方式,开发者可以更好地利用这一工具来提升代码的灵活性和可维护性。

    AOP-CGLIB学习-实现简单的注解权限系统

    Spring框架提供了一种实现AOP的方式,它支持基于代理的AOP实现,包括JDK动态代理和CGLIB代理。当目标对象不实现接口时,Spring会使用CGLIB来创建代理对象。 CGLIB(Code Generation Library)是一个代码生成库,它...

    深入浅出CGlib-打造无入侵的类代理 - llying - ITeye技术网站

    CGlib代理的生成过程大致如下: 1. **创建Enhancer对象**:这是CGlib的核心类,它提供了一种创建代理对象的方式。Enhancer接收一个类作为参数,这个类就是被代理的目标类。 2. **设置回调函数**:通过Enhancer的...

    JDK、CGLib动态代理

    在Java开发中,JDK和CGLib是两种常见的实现动态代理的技术,它们允许我们在运行时创建对象的代理,以增强或拦截对象的方法调用。动态代理在AOP(面向切面编程)中扮演着重要角色,使得我们可以方便地添加如日志、...

    简单实现Cglib子类代理

    - Cglib代理相比于基于接口的JDK动态代理,其创建代理对象的速度更快,但运行时的性能略逊色,因为每次调用方法都需要通过子类调用父类方法,增加了额外开销。 总的来说,Cglib子类代理是一种强大的工具,它使得...

Global site tag (gtag.js) - Google Analytics