转载:http://blog.csdn.net/xiaohai0504/article/details/6832990
一、原理
代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。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(!"张三".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();
- } <span style="font-family: Arial, Verdana, sans-serif; white-space: normal; "> </span>
我们这就可以看看客户端的实现了。添加了两个方法用来验证不同用户的权限
- 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();
ok,现在"李四"也可以使用query方法了,其他方法仍然没有权限。
当然这个代理的实现没有任何侵入性,无需强制让dao去实现接口。
相关推荐
Maven坐标:cglib:cglib:3.1; 标签:cglib、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明...
CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,主要用于Java字节码操作和动态代理。与JDK动态代理不同,CGLIB不依赖于接口,而是通过继承目标类来创建代理对象。 1. **CGLIB核心组件**:主要...
CGlib则是Java动态代理的一种实现方式,尤其是在不提供接口的情况下,它通过生成目标类的子类来实现动态代理。 在Java中,JDK自带的动态代理机制是基于接口的,如果被代理的类没有实现任何接口,那么就无法使用JDK...
与JDK动态代理不同,CGLIB并不依赖接口,而是通过字节码技术生成一个被代理类的子类来实现。这使得CGLIB能够代理没有实现接口的类。CGLIB的核心是ASM库,它能直接操作字节码生成新的类。在Spring中,如果目标类没有...
Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...
CGLIB 动态代理可以代理没有接口的类,這是因为 CGLIB 动态代理可以生成一个原类的子类,然后 override 原类的方法来实现代理。 在 Spring AOP 框架中,默认情况下,Spring 会选择使用 JDK 动态代理,但是如果目标...
CGLib动态代理是一种在Java编程中实现动态代理的技术,它主要通过字节码操作库ASM来生成目标类的子类,从而实现对目标类的方法拦截和增强。在Java中,当我们需要在运行时动态地创建对象并扩展其功能时,CGLib是一个...
相反,CGLIB(Code Generation Library)是一种字节码生成库,它可以创建一个目标类的子类并覆盖其方法,以此实现动态代理。CGLIB使用ASM库来操作字节码,因此它不需要目标类实现任何接口,这使得它能应用于没有接口...
CGlib动态代理是Java开发中一个非常重要的工具库,它主要用来实现代理模式,尤其在面向切面编程(AOP)中发挥着关键作用。CGlib是一个强大的高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。CGlib并不...
CGLib,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在Java世界中被广泛应用,尤其是在动态代理和AOP(面向切面编程)领域。这个库的主要功能是能够在运行时动态创建类或者增强已有类的功能...
本资源提供的示例涵盖了这些核心概念,通过JDK动态代理、CGLIB动态代理以及拦截器链的实践,帮助开发者深入理解并掌握这些技术。 首先,让我们来探讨JDK动态代理。Java标准库中的`java.lang.reflect.Proxy`类和`...
Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建对象的代理,从而可以在不修改原有代码的情况下,对对象的行为进行扩展或增强。Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理...
1. **原理**:JDK动态代理通过`Proxy.newProxyInstance()`方法创建代理对象,该方法接受三个参数:一个类加载器、一个接口数组和一个`InvocationHandler`实例。类加载器用于生成代理类,接口数组定义了代理对象需要...
CGLib,全称为Code Generation Library,是一个强大的Java字节码操作库,广泛应用于动态代理、AOP(面向切面编程)以及性能优化等领域。它允许开发者在运行时创建和增强新的类或对象,而无需编写任何Java源代码。...
在Java开发中,CGLIB经常被用作AOP(面向切面编程)的底层实现,例如Spring框架就使用了CGLIB来实现对目标类的动态代理。 CGLIB是通过字节码技术来实现动态代理的。当我们的应用程序需要动态地创建一个类的实例或者...
本文主要介绍 Java 中两种常见的动态代理方式:JDK 原生动态代理和 CGLIB 动态代理。 一、 代理模式 代理模式是指程序通过代理类来访问目标对象,以达到对目标对象的控制和增强。代理模式的优点是可以在不改变目标...
cglib动态代理需要的jar包下载:cglib动态代理类所需的jar包 ,一共5个jar包,asm-3.3.1.jar、cglib.jar、cglib-full.jar、cglib-nodep-2.1_3.jar、cglib-src-2.2.jar
Cglib 动态代理的实现方式是:我们首先需要定义一个类,然后使用 Cglib 库来生成该类的代理对象,该代理对象将拦截对被代理对象的所有方法调用,并控制对被代理对象的访问。 Cglib 动态代理的优点是:它的实现方式...