`

cglib动态代理介绍

    博客分类:
  • Java
阅读更多

 

一、原理

      代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,当它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包。

 

二、什么是cglib

     CGLIB是一个强大的高性能的代码生成包。

      1>它广泛的被许多AOP的框架使用,例如:Spring AOP和dynaop,为他们提供方法的interception(拦截);

       2>hibernate使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的);

       3>EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。

     它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。

 

三、底层

      CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类。除了CGLIB包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。当不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。所以cglib包要依赖于asm包,需要一起导入。下图为cglib与一些框架和语言的关系(CGLIB Library and ASM Bytecode Framework)


  Spring AOP和Hibernate同时使用JDK的动态代理和CGLIB包。Spring AOP,如果不强制使用CGLIB包,默认情况是使用JDK的动态代理来代理接口。

 

 

四、实例场景模拟

1. 我们创建一个对Table操作的DAO类,提供了CRUD方法。 
    BookServiceBean.java

 

package com.tech.cglibx;  
public class BookServiceBean {  
 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实例。

 

 

package com.tech.cglibx;  
public class BookServiceFactory {  
 private static BookServiceBean service = new BookServiceBean();  
 private BookServiceFactory() {  
 }  
 public static BookServiceBean getInstance() {  
  return service;  
 }  
}  

     接下来我们创建客户端,用来调用CRUD方法。

 

 

public class Client {     
    
    public static void main(String[] args) {     
        BookServiceBean service = BookServiceFactory.getInstance();   
        doMethod(service);     
    }     
    public static void doMethod(BookServiceBean service){     
        service.create();  
        service.update();  
        service.query();  
        service.delete();   
    }     
}   

     OK,完成了,CRUD方法完全被调用了。

 

    当然这里并没有CGlib的任何内容。问题不会这么简单的就结束,新的需求来临了。

2. one day,Boss告诉我们这些方法不能开放给用户,只有“boss”才有权使用。怎么办,难道我们要在每个方法上面进行判断吗?好像这么做也太那啥了吧?对了,Proxy可能是最好的解决办法。jdk的代理就可以解决了。 好了我们来动手改造吧。等等jdk的代理需要实现接口,这样, 我们的dao类需要改变了。既然不想改动dao又要使用代理,我们这就请出CGlib。
我们只需新增一个权限验证的方法拦截器。

package com.tech.cglibx;  
import java.lang.reflect.Method;  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
import org.apache.log4j.Logger;  
public class MyCglibProxy implements MethodInterceptor{  
 private Logger log=Logger.getLogger(MyCglibProxy.class);  
 public Enhancer enhancer = new Enhancer();  
 private String name;  
   
 public MyCglibProxy(String name) {  
       this.name = name ;  
 }  
 /** 
  * 根据class对象创建该对象的代理对象 
  * 1、设置父类;2、设置回调 
  * 本质:动态创建了一个class对象的子类 
  *  
  * @param cls 
  * @return 
  */  
 public Object getDaoBean(Class cls) {  
  enhancer.setSuperclass(cls);  
  enhancer.setCallback(this);  
  return enhancer.create();  
 }  
   
 @Override  
 public Object intercept(Object object, Method method, Object[] args,  
   MethodProxy methodProxy) throws Throwable {  
  log.info("调用的方法是:" + method.getName());  
  //用户进行判断  
  if(!"boss".equals(name)){   
   System.out.println("你没有权限!");   
   return null;   
  }   
  Object result = methodProxy.invokeSuper(object, args);  
    
  return result;  
 }  
}  

 当然不能忘了对我们的dao工厂进行修改,我们提供一个使用代理的实例生成方法。上面的类中已经提供了一个通用的获取代理实例的方法,没有特殊需求(如下3)的方式可以使用上面的方式获取代理对象。

public static BookServiceBean getProxyInstance(MyCglibProxy myProxy){    
     Enhancer en = new Enhancer();     
     //进行代理     
     en.setSuperclass(BookServiceBean.class);     
     en.setCallback(myProxy);     
     //生成代理实例     
     return (BookServiceBean)en.create();     
 } 

 我们这就可以看看客户端的实现了。添加了两个方法用来验证不同用户的权限

BookServiceBean service = BookServiceFactory.getProxyInstance(new MyCglibProxy("boss"));  
service.create();  
BookServiceBean service2 = BookServiceFactory.getProxyInstance(new MyCglibProxy("john"));  
service2.create();


OK,"boss"的正常执行,"john"的没有执行。 

看到了吗?简单的aop就这样实现了 
难道就这样结束了么?

 

 3.grd Boss又来训话了,不行不行,现在除了"boss"其他人都用不了了,现在不可以这样。必须使用开放查询功能。 哈哈,现在可难不倒我们了,因为我们使用了CGlib。当然最简单的方式是去修改我们的方法拦截器,不过这样会使逻辑变得复杂,且不利于维护。还好CGlib给我们提供了方法过滤器(CallbackFilter),CallbackFilte可以明确表明,被代理的类中不同的方法,被哪个拦截器所拦截。下面我们就来做个过滤器用来过滤query方法。

package com.tech.cglibx;  
import java.lang.reflect.Method;  
import net.sf.cglib.proxy.CallbackFilter;  
public class MyProxyFilter implements CallbackFilter {  
 @Override  
 public int accept(Method arg0) {     
        if(!"query".equalsIgnoreCase(arg0.getName()))     
            return 0;     
        return 1;     
    }  
}  

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

public static BookServiceBean getAuthInstanceByFilter(MyCglibProxy myProxy){    
     Enhancer en = new Enhancer();     
     en.setSuperclass(BookServiceBean.class);     
     en.setCallbacks(new Callback[]{myProxy,NoOp.INSTANCE});     
     en.setCallbackFilter(new MyProxyFilter());     
     return (BookServiceBean)en.create();     
 }  

  setCallbacks中定义了所使用的拦截器,其中NoOp.INSTANCE是CGlib所提供的实际是一个没有任何操作的拦截器, 他们是有序的,一定要和CallbackFilter里面的顺序一致。上面return返回(0/1)的就是返回的顺序。也就是说如果调用query方法就使用NoOp.INSTANCE进行拦截。

现在看一下客户端代码。
BookServiceBean service = BookServiceFactory.getProxyInstanceByFilter(new MyCglibProxy("jhon"));  
 service.create();  
 BookServiceBean service2 = BookServiceFactory.getProxyInstanceByFilter(new MyCglibProxy("jhon"));  
 service2.query();  

  

  • 大小: 14 KB
  • 大小: 3.7 KB
分享到:
评论

相关推荐

    转载:cglib动态代理介绍(一)

    - 如果目标类中包含静态方法,CGlib代理不会影响静态方法的行为。 总结,CGlib是一个强大且灵活的工具,它通过字节码生成技术实现了对Java类的动态代理,尤其在没有接口约束或者性能要求高的情况下,它是Java开发者...

    Jdk动态代理和cglib动态代理原理

    - **CGLIB代理**适用于目标类没有接口或者不希望修改原有接口的情况,其性能通常优于JDK代理,因为它是基于字节码生成的子类,而JDK代理需要反射调用接口方法。 在实际开发中,如Spring AOP框架就同时支持JDK和...

    Spring框架中JDK动态代理和cglib动态代理

    Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...

    AOP之JDK动态代理和CGLib动态代理

    Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...

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

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

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

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

    Jdk动态代理,cglib动态代理,反射和拦截器(链)示例

    本资源提供的示例涵盖了这些核心概念,通过JDK动态代理、CGLIB动态代理以及拦截器链的实践,帮助开发者深入理解并掌握这些技术。 首先,让我们来探讨JDK动态代理。Java标准库中的`java.lang.reflect.Proxy`类和`...

    cglib动态代理jar包

    CGlib动态代理是Java开发中一个非常重要的工具库,它主要用来实现代理模式,尤其在面向切面编程(AOP)中发挥着关键作用。CGlib是一个强大的高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。CGlib并不...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    本文主要介绍 Java 中两种常见的动态代理方式:JDK 原生动态代理和 CGLIB 动态代理。 一、 代理模式 代理模式是指程序通过代理类来访问目标对象,以达到对目标对象的控制和增强。代理模式的优点是可以在不改变目标...

    基于MAVEN项目的CGLib动态代理原理及实现

    本文将深入探讨如何在基于Maven的项目中利用CGLib库实现动态代理。CGLib(Code Generation Library)是Java中一个高性能的代码生成库,它在运行期通过字节码技术为类创建子类,以此实现动态代理。 1. Maven项目配置...

    CGlib动态代理类的jar包

    CGlib是Java动态代理的一种实现方式,它不是依赖于Java的反射机制,而是通过生成目标类的子类来实现代理,因此在性能上通常优于基于接口的JDK动态代理。 CGlib动态代理的核心类包括`Enhancer`、`Callback`和`...

    jdk和cglib动态代理的例子{jar包+源码}

    jdk和cglib动态代理的例子{jar包+源码} 解压:如有问题 用快压

    输出JDK和CGLib动态代理产生的class文件.zip

    2. CGLib代理项目: - src/main/java:包含目标类 - target/classes:编译后的class文件,包括目标类的class文件,以及由CGLib生成的子类class文件 - 测试代码:展示如何使用Enhancer创建代理对象并调用方法 这...

    CgLib动态代理所需的jar

    CgLib就是实现这种动态代理的一个工具,特别是在不支持接口的类上。 CgLib的核心功能是通过字节码技术创建子类。当目标类没有实现接口时,Java的标准动态代理机制JDK Proxy就无法工作,因为JDK Proxy是基于接口的。...

    CGLIB动态代理+CGLIB动态代理完整代码

    我们最终是通过一个代理对象去调用方法的,那我们就要获取一个代理对象,cglib代理,是通过Enhancer这个类里面对应的一个create()方法,去生成一个代理对象的。 Enhancer创建一个被代理对象的子类并且拦截所有的方法...

    cglib动态代理相关包

    CGlib是Java编程语言中的一个库,主要用于生成子类,以提供方法拦截和动态代理功能。它是对Bytecode Generation Library(字节码生成库)的一个封装,能够在运行时动态创建新类和对象,广泛应用于AOP(面向切面编程...

    CGlib实现动态代理(承接上面JDK实现动态代理)

    CGlib是Java编程语言中的一个库,主要用于生成子类,以此实现对现有类的动态代理。它是基于ASM库,能够直接操作字节码,从而在运行时创建新类的实例。在Java中,CGlib是一个非常重要的工具,特别是在AOP(面向切面...

    JDK动态代理和CGLIB代理

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

Global site tag (gtag.js) - Google Analytics