`
zhangxiaofei13
  • 浏览: 3947 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

CGLIB解析

阅读更多

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

cglib封装了asm,可以在运行期动态生成新的class。
cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。

这里必须说一下ASM

 

 

ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
与 BCEL 和 SERL 不同,ASM 提供了更为现代的编程模型。对于 ASM 来说,Java class 被描述为一棵树;使用 “Visitor” 模式遍历整个二进制结构;事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解 Java 类文件格式的所有细节:ASM 框架提供了默认的 “response taker”处理这一切。
为什么要动态生成 Java 类?
动态生成 Java 类与 AOP 密切相关的。AOP 的初衷在于软件设计世界中存在这么一类代码,零散而又耦合:零散是由于一些公有的功能(诸如著名的 log 例子)分散在所有模块之中;同时改变 log 功能又会影响到所有的模块。出现这样的缺陷,很大程度上是由于传统的 面向对象编程注重以继承关系为代表的“纵向”关系,而对于拥有相同功能或者说方面 (Aspect)的模块之间的“横向”关系不能很好地表达。例如,目前有一个既有的银行管理系统,包括 Bank、Customer、Account、Invoice 等对象,现在要加入一个安全检查模块, 对已有类的所有操作之前都必须进行一次安全检查。

ASM 能够通过改造既有类,直接生成需要的代码。增强的代码是硬编码在新生成的类文件内部的,没有反射带来性能上的付出。同时,ASM 与 Proxy 编程不同,不需要为增强代码而新定义一个接口,生成的代码可以覆盖原来的类,或者是原始类的子类。它是一个普通的 Java 类而不是 proxy 类,甚至可以在应用程序的类框架中拥有自己的位置,派生自己的子类。
相比于其他流行的 Java 字节码操纵工具,ASM 更小更快。ASM 具有类似于 BCEL 或者 SERP 的功能,而只有 33k 大小,而后者分别有 350k 和 150k。同时,同样类转换的负载,如果 ASM 是 60% 的话,BCEL 需要 700%,而 SERP 需要 1100% 或者更多。
ASM 已经被广泛应用于一系列 Java 项目:AspectWerkz、AspectJ、BEA WebLogic、IBM AUS、OracleBerkleyDB、Oracle TopLink、Terracotta、RIFE、EclipseME、Proactive、Speedo、Fractal、EasyBeans、BeanShell、Groovy、Jamaica、CGLIB、dynaop、Cobertura、JDBCPersistence、JiP、SonarJ、Substance L&F、Retrotranslator 等。Hibernate 和 Spring 也通过 cglib,另一个更高层一些的自动代码生成工具使用了 ASM。

 

 下面看一个简单的例子,具体的体会一下CGLIB的实现方式:

   Option操作类含义基本的操作类型增删改查 

package cglib;

import java.io.Serializable;

/**
 * 操作集合实现类
 * @author zhangjuwei
 *
 */
public class Option implements Serializable {

	public  void  add(){
		System.out.println(" add opt");
	}
	
	public  void  update(){
		System.out.println(" update opt");
	}
	
	public  void  query(){
		System.out.println(" query opt");
	}
	
	public  void  del(){
		System.out.println(" del opt");
	}
	
	
}

 

 操作工厂类,单例的获取操作对象
package cglib;

import net.sf.cglib.proxy.Enhancer;

/**
* 操作工厂类
* @author zhangjuwei
*
*/
public class OptionFactory {

private static Option option = new Option();

public static Option getInstance() {
return option;
}

}

 

  这时 基本上可以满足常见的需求了。即调用操作类中的四个方法。

详见 Client 的 7 8 行。 

 

但如果要实现比较复杂的需求如:某些方法某些人的访问权限的限制。

看下面的代码:OptionFactory4Auth 

   

package cglib;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;

/**
 * 操作工厂类
 * @author zhangjuwei
 *
 */
public class OptionFactory4Auth {

	 public static Option getAuthInstance(AuthOptProxy auth) {
		 	System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C://temp");  //这里将生成的class文件输出至指定的文件夹下,方便查看。
	        Enhancer enhancer = new Enhancer();  //底层是ASM
	        enhancer.setSuperclass(Option.class);
//	        enhancer.setCallback(auth);
	        
	        enhancer.setCallbacks(new Callback[] { auth, NoOp.INSTANCE });
	        enhancer.setCallbackFilter(new AuthProxyFilter());    
	        return (Option) enhancer.create();
	        
	        
	    }
	
}

 

 

package cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.CallbackFilter;

public class AuthProxyFilter implements CallbackFilter {

	private static final int AUTH_NEED = 0;
	private static final int AUTH_NOT_NEED = 1;

	@Override
	public int accept(Method method) {
		if ("query".equals(method.getName())) {
			return AUTH_NOT_NEED;
		}
		return AUTH_NEED;
	}

}

 

package cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 用户权限校验类
 * @author zhangjuwei
 *
 */
public class AuthOptProxy implements MethodInterceptor{

	private String name;
	
	public AuthOptProxy(String name) {
		super();
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@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);
	}
	
}

 

package cglib;


public class Client {

	public static void main(String[] args) {
		Client c = new Client();
		// c.optManage();
		c.haveNoAuthManager();
		c.haveAuthManager();
	}

	/**
	 * 模拟:登录会员没有权限
	 * 
	 */
	public void haveNoAuthManager() {
		System.out.println("the loginer's name is not maurice,so have no permits do manager");
		Option noAuthManager = OptionFactory4Auth.getAuthInstance(new AuthOptProxy("maurice1"));
		doCRUD(noAuthManager);
	}

	/**
	 * 模拟:登录会员有权限
	 */
	public void haveAuthManager() {
		System.out
				.println("the loginer's name is  maurice,so have  permits do manager");
		Option noAuthManager = OptionFactory4Auth
				.getAuthInstance(new AuthOptProxy("maurice"));
		doCRUD(noAuthManager);
	}

	public void optManage() {
		System.out.println("any one can do manager");
		Option option = OptionFactory.getInstance();
		doCRUD(option);
	}

	public void doCRUD(Option opt) {
		opt.add();
		opt.update();
		opt.del();
		opt.query();
	}

}

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

分享到:
评论

相关推荐

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

    NULL 博文链接:https://tpglzu2015.iteye.com/blog/2202987

    spring-cglib-repack-3.1.jar

    学spring的应该知道要熟悉spring的源码,本人是根据《spring源码深度解析》里的步骤下载了spring的源码,也使用gradle编译了一下,终于可以导入eclipse了,但是jar包依赖报错了,就是缺少spring-cglib-repack-3.1....

    spring-cglib-repack-3.2.0.jar和spring-objenesis-repack-2.1.jar.zip

    Spring源码深度解析中的两个jar包,文章课件需要的小伙伴可以下载,spring-cglib-repack-3.2.0.jar和spring-objenesis-repack-2.1.jar.zip

    spring-cglib-repack-3.2.6 和 spring-objenesis-repack-2.6

    spring源码解析时,需要额外引入的最新jar包,注意版本号,使用时把最后的.0去掉即可

    spring源代码解析需要的额外包

    由于原始的《spring源代码解析》导入eclipse工程会出现缺少jar包出现错误,所以进行spring lib的jar重新打包,包括spring-cglib-repack-3.2.0.jar和spring-objenesis-repack-2.2.jar,已验证可用。

    spring-cglib-repack-3.2.5.jar spring-objenesis-repack-2.6.jar

    推荐这篇文章:http://blog.csdn.net/surp2011/article/details/50776013 《Spring源码深度解析》 第二章导入项目 缺少的jar

    hibernate核心包

    dom4j-1.6.1.jar dom4j XML 解析器 jta-1.1.jar 标准的 JAVA 事务处理接口 javassist-3.9.0.GA.jar 代码生成工具 (Hibernate用它在运行时扩展 Java类和实现,同cglib包) slf4j-api-1.5.8.jar和slf4j-log4j12-1.5.0....

    Mybatis的Mapper方式整合elasticsearch的DSL调用,基于接口和代理生成bean注入的方式进行调用

    Mybatis的Mapper方式整合elasticsearch的DSL调用,之前的AOP进行了改进,使用cglib动态代理生成代理类,基于接口和代理生成bean注入的方式进行调用

    Spring AOP源码深度解析:掌握Java高级编程核心技术

    动态代理是实现AOP的基础,它通过JDK动态代理或CGLIB代理生成被代理对象的子类。通知是织入到目标对象连接点上的一段程序,例如@Before、@After等。 切点定义了通知应该在哪些连接点上触发。而切面则是通知和切点的...

    SpringBoot下的SpringAOP-day04-源代码

    2.5 关于切入点表达式解析 2.5.1 bean标签写法 2.5.2 within表达式 2.5.3 execution表达式 2.6 按照自定义注解进行拦截 2.6.1 自定义注解 2.6.2 切入点表达式写法 2.6.3 在service层实现类UserServiceImpl的addUser...

    Spring CGLlB动态代理实现过程解析

    主要介绍了Spring CGLlB动态代理实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    动态代理.xmind

    该思维导图主要讲解了代理模式的具体实现,包括jdk代理,cglib代理。其中jdk代理主要讲解了其具体的实现方式、原理...Cglib代理主要讲解了其原理、与JDK代理的对比、Enhancer源码解析、methodProxy和Fastclass源码等。

    JavaEE求职简历-姓名-JAVA开发工程师-范文.doc

    3年JAVA开发经验,有多个项目开发经验,可独立开发; ...熟练掌握Spring IOC、AOP 的使用和实现原理,掌握java内部面向接口,实现InvocationHandler的动态代理,和Cglib面向父类,实现MethodIn

    web开发常用jar

    CGLIB是一个强大的高质量高性能的代码生成库,在运行时可以用它来扩展Java类 jfreechart-1.0.12.jar 使用java生成图表的工具 log4j-1.2.15.jar 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、...

    spring(1)

    模仿spring写的一个小型框架,教学时使用。涉及到的知识点有:java反射机制,动态代理,CGLIB,IOC和AOP,以及用dom4j解析xml文件和dtd的使用。

    java代码自动生成源码-AutoInterface:自动生成Java接口源代码

    Spring运行时注入默认情况下需要一个Interface,否则spring使用CGLIB代理。 通过自动生成接口,您不需要使用CGLIB并受其限制。 帮助第三方生成代码或您想保留其final类别的类 用法 // Reference dependency ...

    java开发常用jar包

    CGLIB是一个强大的高质量高性能的代码生成库,在运行时可以用它来扩展Java类 jfreechart-1.0.12.jar 使用java生成图表的工具 log4j-1.2.15.jar 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、...

    lw_reptile:图片爬虫-

    6.cglib实现动态代理,自定义注释解运用,反射以及设计模式的使用。 7.爬虫监控信息。 8.log4j日志拦截并输出到界面,以及日志文件记录。 9.多线程高并发以及线程池定时任务实现。 10.线程安全以及高速高性能...

    SSH 框架所需JAR包

    6.cglib-nodep-2.1_3.jar(支持cglib动态代理的包) 如果用BasicDataSource来配置数据库连接,还要加入2个包: 7.commons-pool.jar 8.commons-dbcp.jar Hibernate需要的jar包: 1.hibernate3.jar(hibernate的核心jar...

Global site tag (gtag.js) - Google Analytics