cglib使用
cglib,全称是Code Generation Library,它可以用来动态继承Java类或者实现接口,很多知名的开源项目中用到了它,譬如Hibernate,Spring之类用它来实现动态代理。
增强一个已有类
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback( new MethodInterceptorImpl() );
MyClass my = (MyClass)enhancer.create();
my.method();
}
private static class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method);
proxy.invokeSuper(obj, args);
return null;
}
}
}
执行结果:
public void cglib_test.MyClass.method()
MyClass.method()
使用CallbackFilter
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
public void method2() {
System.out.println("MyClass.method2()");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
public class Main {
public static void main(String[] args) {
Callback[] callbacks =
new Callback[] { new MethodInterceptorImpl(), NoOp.INSTANCE };
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallbacks( callbacks );
enhancer.setCallbackFilter( new CallbackFilterImpl() );
MyClass my = (MyClass)enhancer.create();
my.method();
my.method2();
}
private static class CallbackFilterImpl implements CallbackFilter {
public int accept(Method method) {
if ( method.getName().equals("method2") ) {
return 1;
} else {
return 0;
}
}
}
private static class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method);
return proxy.invokeSuper(obj, args);
}
}
}
执行结果:
public void cglib_test.MyClass.method()
MyClass.method()
MyClass.method2()
使用Mixin
public interface MyInterfaceA {
public void methodA();
}
public interface MyInterfaceB {
public void methodB();
}
public class MyInterfaceAImpl implements MyInterfaceA {
public void methodA() {
System.out.println("MyInterfaceAImpl.methodA()");
}
}
public class MyInterfaceBImpl implements MyInterfaceB {
public void methodB() {
System.out.println("MyInterfaceBImpl.methodB()");
}
}
import net.sf.cglib.proxy.Mixin;
public class Main {
public static void main(String[] args) {
Class[] interfaces =
new Class[] { MyInterfaceA.class, MyInterfaceB.class };
Object[] delegates =
new Object[] { new MyInterfaceAImpl(), new MyInterfaceBImpl() };
Object obj = Mixin.create(interfaces, delegates);
MyInterfaceA myA = (MyInterfaceA)obj;
myA.methodA();
MyInterfaceB myB = (MyInterfaceB)obj;
myB.methodB();
}
}
执行结果:
MyInterfaceAImpl.methodA()
MyInterfaceBImpl.methodB()
在多层结构体系中,我们经常要大量的在对象之间拷贝属性,使用jakarta的commons BeanUtils工具类是我们省去了重复的set,get体力活,但带来之的却是性能的损失,BeanUtils用反射来完成功能,当然在对象的数量相对较少时,这点性能是可以忽略的,但当对象数量很大时,不得不考虑能否采用更好的解决方案. Cglib提供了类似的功能,以字节码增强的形式.我小测了二者之间的性能.大量Bean的拷贝,cglib比beanutils性能好了一个数量级,
/* * Created on 2005-5-1 * */
package org.jjyao.cglib;
import net.sf.cglib.beans.BeanCopier;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
/**
* FinalCheat
*
* @author jjyao 2005-5-1
*/
public class PropertyCopyTest {
static final private Logger logger = Logger.getLogger(PropertyCopyTest.class);
public static class Other {
String userName;
String password;
int age;
String dateTime;
/**
* @return Returns the age.
*/
public int getAge() {
return age;
}
/**
* @param age
* The age to set.
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return Returns the dateTime.
*/
public String getDateTime() {
return dateTime;
}
/**
* @param dateTime
* The dateTime to set.
*/
public void setDateTime(String dateTime) {
this.dateTime = dateTime;
}
/**
* @return Returns the password.
*/
public String getPassword() {
return password;
}
/**
* @param password
* The password to set.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return Returns the userName.
*/
public String getUserName() {
return userName;
}
/**
* @param userName
* The userName to set.
*/
public void setUserName(String userName) {
this.userName = userName;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Other[");
sb.append("UserName=");
sb.append(this.userName);
sb.append(",");
sb.append("Password=");
sb.append(this.password);
sb.append(",");
sb.append("Age=");
sb.append(this.age);
sb.append(",");
sb.append("DateTime=");
sb.append(this.dateTime);
sb.append("]");
return sb.toString();
}
}
public static class Myth {
String userName;
String password;
int age;
long dateTime;
/**
* @return Returns the dateTime.
*/
public long getDateTime() {
return dateTime;
}
/**
* @param dateTime
* The dateTime to set.
*/
public void setDateTime(long dateTime) {
this.dateTime = dateTime;
}
/**
* @return Returns the age.
*/
public int getAge() {
return age;
}
/**
* @param age
* The age to set.
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return Returns the password.
*/
public String getPassword() {
return password;
}
/**
* @param password
* The password to set.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return Returns the userName.
*/
public String getUserName() {
return userName;
}
/**
* @param userName
* The userName to set.
*/
public void setUserName(String userName) {
this.userName = userName;
}
}
private Myth init() {
Myth myth = new Myth();
myth.setUserName("jjyao");
myth.setPassword("1111");
myth.setAge(24);
myth.setDateTime(System.currentTimeMillis());
return myth;
}
public static void main(String[] args) throws Exception {
String argument = null;
if (args != null && args.length > 0) {
argument = args[0];
} else {
throw new IllegalArgumentException("invalid args ");
}
Other other = new Other();
Myth myth = new PropertyCopyTest().init();
if ("cglib".equals(argument)) {
BeanCopier copier = BeanCopier.create(Myth.class, Other.class, false);
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
copier.copy(myth, other, null);
}
logger.info("" + other);
logger.info(" Use Cglib,It costs time : " + (System.currentTimeMillis() - beginTime));
} else if ("beanUtil".equals(argument)) {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
BeanUtils.copyProperties(other, myth);
}
logger.info("" + other);
logger.info(" Use BeanUtils,It costs time : " + (System.currentTimeMillis() - beginTime));
}
}
}
java PropertyCopyTest cglib
15:37:53,140 INFO PropertyCopyTest:214 - Use Cglib,It costs time : 31
====================
java PropertyCopyTest beanUtil
15:39:15,046 INFO PropertyCopyTest:224 - Use BeanUtils,It costs time : 3546