1、cglib是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO字节码的动态生成。
2、代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包。
3、CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
4、CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉
5、创建一个简单的代理类:
package com.sxit;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @功能:
* @作者:smile
* @时间:2013-3-4 上午11:23:39
* @版本: 1.0
*/
public class proxyUtil implements MethodInterceptor {
private Object target;
public proxyUtil(){}
//通过构造函数传入需要代理的目标对象
public proxyUtil(Object target){
this.target = target;
}
//这里类似一个拦截器 在方法调用前后编制业务逻辑
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method+"方法开始前...");
//调用原来的方法
Object o = proxy.invokeSuper(target, args);
System.out.println(method+"方法结束了...");
System.out.println("返回对象为:"+o);
return o;
}
}
6、一个简单的接口和它的实现类:
package com.sxit;
/**
* @功能:
* @作者:smile
* @时间:2013-3-4 上午11:22:32
* @版本: 1.0
*/
public interface Person {
/**
* @功能:说话
*/
public String say(String name);
/**
* @功能:看
*/
public String look(String name);
}
package com.sxit;
/**
* @功能:
* @作者:smile
* @时间:2013-3-4 上午11:23:08
* @版本: 1.0
*/
public class Chinese implements Person {
public String say(String name) {
System.out.println("打印>>>>>>你好:"+name);
return "你好:"+name;
}
public String look(String name) {
System.out.println("打印>>>>>>我看到:"+name);
return "我看到:"+name;
}
}
7、创建代理:
package com.sxit;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
//需要被代理的目標對象
Chinese c = new Chinese();
Enhancer hancer = new Enhancer();
//通过继承目标对象来实现代理 所以目标对象一定要有一个默认无参构造函数 反射的时候需要实例化父类对象
hancer.setSuperclass(c.getClass());
//设置代理回调函数
hancer.setCallback(new proxyUtil(c));
//代理后的对象
Chinese c2 = (Chinese) hancer.create();
c2.say("sb");
c2.look("傻逼");
}
}
8、打印信息:
public java.lang.String com.sxit.Chinese.say(java.lang.String)方法开始前...
打印>>>>>>你好:sb
public java.lang.String com.sxit.Chinese.say(java.lang.String)方法结束了...
返回对象为:你好:sb
public java.lang.String com.sxit.Chinese.look(java.lang.String)方法开始前...
打印>>>>>>我看到:傻逼
public java.lang.String com.sxit.Chinese.look(java.lang.String)方法结束了...
返回对象为:我看到:傻逼
9、CallbackFilter可以实现不同的方法使用不同的回调方法:
package com.sxit;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
public class CallBackFilterImp implements CallbackFilter {
//方法名过滤
public int accept(Method method) {
if(method.getName().equals("say")){
return 0;
}else if(method.getName().equals("look")){
return 1;
}
return 0;
}
}
10、新写一个代理处理类proxyUtil2,只改动了打印信息:
package com.sxit;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @功能:
* @作者:smile
* @时间:2013-3-4 上午11:23:39
* @版本: 1.0
*/
public class proxyUtil2 implements MethodInterceptor {
private Object target;
public proxyUtil2(){}
public proxyUtil2(Object target){
this.target = target;
}
//这里类似一个拦截器 在方法调用前后编制业务逻辑
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method+"方法啦啦啦开始啦...");
//调用原来的方法
Object o = proxy.invokeSuper(target, args);
System.out.println(method+"方法啦啦啦结束啦...");
System.out.println("返回对象为:"+o);
return o;
}
}
11、测试:
package com.sxit;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
// 需要被代理的目標對象
Chinese c = new Chinese();
Enhancer hancer = new Enhancer();
// 通过继承目标对象来实现代理 所以目标对象一定要有一个默认无参构造函数 反射的时候需要实例化父类对象
hancer.setSuperclass(c.getClass());
// 一个回调函数数组
Callback[] callbacks = new Callback[] { new proxyUtil(c), new proxyUtil2(c) };
hancer.setCallbacks(callbacks);
// 设置方法过滤器
hancer.setCallbackFilter(new CallBackFilterImp());
// 代理后的对象
Chinese c2 = (Chinese) hancer.create();
c2.say("sb");
c2.look("傻逼");
}
}
12、打印信息:
public java.lang.String com.sxit.Chinese.say(java.lang.String)方法开始前...
打印>>>>>>你好:sb
public java.lang.String com.sxit.Chinese.say(java.lang.String)方法结束了...
返回对象为:你好:sb
public java.lang.String com.sxit.Chinese.look(java.lang.String)方法啦啦啦开始啦...
打印>>>>>>我看到:傻逼
public java.lang.String com.sxit.Chinese.look(java.lang.String)方法啦啦啦结束啦...
返回对象为:我看到:傻逼
13、注意:
CallBackFilterImp中的return 0和return 1这里的值是指回调数组callbacks数组下表,0则对应proxyUtil这个代理类处理,1则对应proxyUtil2这个代理类处理。