本文的例子全部来自github上cglib的官方文档,有关cglib的教程少之又少,如果想学习觉得还是看看诸如Hibernate和Spring的源码来的实在。
package com.tang;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import net.sf.cglib.beans.BeanCopier;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
import net.sf.cglib.beans.BulkBean;
import net.sf.cglib.beans.ImmutableBean;
import net.sf.cglib.core.KeyFactory;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.InterfaceMaker;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.Mixin;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.reflect.ConstructorDelegate;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import net.sf.cglib.reflect.MethodDelegate;
import net.sf.cglib.reflect.MulticastDelegate;
import net.sf.cglib.util.ParallelSorter;
import net.sf.cglib.util.StringSwitcher;
import org.junit.Test;
import org.objectweb.asm.Type;
import com.pojo.BeanDelegate;
import com.pojo.Class1;
import com.pojo.Class2;
import com.pojo.DelegatationProvider;
import com.pojo.Interface1;
import com.pojo.Interface2;
import com.pojo.MixinInterface;
import com.pojo.OtherSampleClass;
import com.pojo.SampleBeanConstructorDelegate;
import com.pojo.SampleClass;
import com.pojo.SimpleMulticastBean;
/**
* 字节码增强类
*
* @author Administrator
*
*/
public class Cglib {
/**
* 将一个方法的返回值设置为固定的值 使用FixedValue,SimpleClass类的所有方法包括父类的 方法都试图返回"Hello cglib"
*/
@Test
public void testFixedValue() {
Enhancer e = new Enhancer();
e.setSuperclass(SampleClass.class);
e.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Hello cglib";
}
});
SampleClass proxy = (SampleClass) e.create();
assertEquals("Hello cglib", proxy.test(null));
assertEquals("Hello cglib", proxy.toString());
// 调用hashCode方法将返回ClassCastException
try {
proxy.hashCode();
} catch (Exception e1) {
assertEquals(e1.getClass(), ClassCastException.class);
}
// getClass方法为final修饰的,cglib不会对final的方法修饰。
proxy.getClass();
}
/*
* 测试InvocationHandler
*/
@Test
public void testInvocationHandler() {
Enhancer e = new Enhancer();
e.setSuperclass(SampleClass.class);
e.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 对非Object类并且方法的返回值是String类型的方法增强
if (method.getDeclaringClass() != Object.class
&& method.getReturnType() == String.class) {
return "Hello cglib!";
} else {
// 其他方法抛异常
throw new RuntimeException("Do not know what to do.");
// 如果写成下面这种调用本类中的其他方法,则会出现死循环。后面的方法能够解决这个问题
/*
* System.out.println("else"); return method.invoke(proxy,
* args);
*/
}
}
});
SampleClass proxy = (SampleClass) e.create();
assertEquals("Hello cglib!", proxy.test(null));
try {
proxy.hashCode();
} catch (Exception e1) {
assertEquals(e1.getMessage(), "Do not know what to do.");
}
}
/**
* 该方法比InvocationHandler更常用,因为InvocationHandler有死循环的危险
*/
@Test
public void testMethodInterceptor() {
Enhancer e = new Enhancer();
e.setSuperclass(SampleClass.class);
e.setCallback(new MethodInterceptor() {
// 相比invoke方法多出一个MethodProxy,为被代理类原方法的一个包装,有时候因为性能问题我们需要调用原类中的方法
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// 对非Object类并且方法的返回值是String类型的方法增强
if (method.getDeclaringClass() != Object.class
&& method.getReturnType() == String.class) {
return "Hello cglib!";
} else {
// 调用原方法
return proxy.invokeSuper(obj, args);
}
}
});
SampleClass proxy = (SampleClass) e.create();
assertEquals("Hello cglib!", proxy.test(null));
assertEquals(1, proxy.random());
}
/**
* callback的回调可以指定多个,既然有多个回调,那么需要指定一个策略来决定本次 调用要回调哪个
* 下面这个例子类似上面testMethodInterceptor方法。
*/
@Test
public void testCallbackFilter() {
Enhancer e = new Enhancer();
CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class,
new Class[0]) {
/**
* 根据不同的情况返回不同的callback类
*/
@Override
protected Object getCallback(Method method) {
if (method.getDeclaringClass() != Object.class
&& method.getReturnType() == String.class) {
return new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Hello cglib!";
}
};
// 返回原类默认的方法实现
} else {
return NoOp.INSTANCE; // A singleton provided by NoOp.
}
}
};
e.setSuperclass(SampleClass.class);
e.setCallbackFilter(callbackHelper);
e.setCallbacks(callbackHelper.getCallbacks());
SampleClass proxy = (SampleClass) e.create();
assertEquals("Hello cglib!", proxy.test(null));
assertNotSame("Hello cglib!", proxy.random());
}
/**
* 创建不可变的bean
*/
@Test
public void testImmutableBean() {
SampleClass sample = new SampleClass();
sample.setValue("Hello world!");
SampleClass immutable = (SampleClass) ImmutableBean.create(sample);
assertEquals("Hello world!", immutable.getValue());
sample.setValue("Hello world again!");
assertEquals("Hello world again!", sample.getValue());
immutable.setValue("!");// 报错,因为immutable是不可变的bean
}
/**
* bean生成器,动态生成bean
*
* @throws NoSuchMethodException
* @throws SecurityException
*/
@Test
public void testBeanGenerator() throws Exception {
BeanGenerator generator = new BeanGenerator();
generator.addProperty("value", String.class);
Object bean = generator.create();
Method setter = bean.getClass().getMethod("setValue", String.class);
setter.invoke(bean, "Hello world!");
Method getter = bean.getClass().getMethod("getValue");
assertEquals("Hello world!", getter.invoke(bean));
}
/**
* 属性拷贝器,如果两个类有相同的属性,则该拷贝器起作用
*/
@Test
public void testBeanCopier() {
BeanCopier copier = BeanCopier.create(SampleClass.class,
OtherSampleClass.class, false);
SampleClass bean = new SampleClass();
bean.setValue("Hello cglib!");
OtherSampleClass otherBean = new OtherSampleClass();
copier.copy(bean, otherBean, null);
assertEquals("Hello cglib!", otherBean.getValue());
}
/**
* bulkbean将一个bean中的get,set,返回值 分别看做一一对应的数组
*/
@Test
public void testBulkBean() {
BulkBean bulkBean = BulkBean.create(SampleClass.class,
new String[] { "getValue" }, new String[] { "setValue" },
new Class[] { String.class });
SampleClass bean = new SampleClass();
bean.setValue("Hello world!");
assertEquals(1, bulkBean.getPropertyValues(bean).length);
assertEquals("Hello world!", bulkBean.getPropertyValues(bean)[0]);
bulkBean.setPropertyValues(bean, new Object[] { "Hello cglib!" });
assertEquals("Hello cglib!", bean.getValue());
}
/**
* cglib中的最后一个工具类,将bean的所有属性转换成key-map的形式
*/
@Test
public void testBeanMap() {
SampleClass bean = new SampleClass();
bean.setValue("Hello world!");
BeanMap map = BeanMap.create(bean);
assertEquals("Hello world!", map.get("value"));
}
/**
* keyfactory能够创建key的实例,key可以由不同的值组成,能够被map来使用
* 想要使用该功能需要定义一个接口,该接口必须有一个newInstance方法,且返回Object
*/
@Test
public void testKeyFactory() {
SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory
.create(SampleKeyFactory.class);
// foo和42共同作为key
Object key = keyFactory.newInstance("foo", 42);
Map<Object, String> map = new HashMap<Object, String>();
map.put(key, "Hello cglib!");
assertEquals("Hello cglib!", map.get(keyFactory.newInstance("foo", 42)));
}
/**
* Mixin可以对多个对象进行代理,需要同时指定多个接口和者多个接口对应的代理对象
*/
@Test
public void testMixin() {
Mixin mixin = Mixin.create(new Class[] { Interface1.class,
Interface2.class, MixinInterface.class }, new Object[] {
new Class1(), new Class2() });
MixinInterface mixinDelegate = (MixinInterface) mixin;
assertEquals("first", mixinDelegate.first());
assertEquals("second", mixinDelegate.second());
}
/**
* stringswitcher将在string和int之间建立一种映射,java 7已经内建的支持该 功能了。
*
* @throws Exception
*/
@Test
public void testStringSwitcher() throws Exception {
String[] strings = new String[] { "one", "two" };
int[] values = new int[] { 10, 20 };
StringSwitcher stringSwitcher = StringSwitcher.create(strings, values,
true);
assertEquals(10, stringSwitcher.intValue("one"));
assertEquals(20, stringSwitcher.intValue("two"));
assertEquals(-1, stringSwitcher.intValue("three"));
}
/**
* 运行时生成接口,依赖ASM
*/
@Test
public void testInterfaceMaker() {
Signature signature = new Signature("foo", Type.DOUBLE_TYPE,
new Type[] { Type.INT_TYPE });
InterfaceMaker maker = new InterfaceMaker();
maker.add(signature, new Type[0]);
Class iface = maker.create();
assertEquals(1, iface.getMethods().length);
assertEquals("foo", iface.getMethods()[0].getName());
assertEquals(double.class, iface.getMethods()[0].getReturnType());
}
/**
* 方法代理
*
* @throws Exception
*/
@Test
public void testMethodDelegate() throws Exception {
SampleClass bean = new SampleClass();
bean.setValue("Hello cglib!");
// 使用BeanDelegate代理sampleclass的getValue方法
BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(bean,
"getValue", BeanDelegate.class);
assertEquals("Hello cglib!", delegate.getValue());
}
/**
* 可以代理多个对象 被代理的对象需要实现一个只有一个方法的对象。
*
* @throws Exception
*/
@Test
public void testMulticastDelegate() throws Exception {
MulticastDelegate multicastDelegate = MulticastDelegate
.create(DelegatationProvider.class);
SimpleMulticastBean first = new SimpleMulticastBean();
SimpleMulticastBean second = new SimpleMulticastBean();
// 链式编程
multicastDelegate = multicastDelegate.add(first).add(second);
DelegatationProvider provider = (DelegatationProvider) multicastDelegate;
// 代理first和second
provider.setValue("Hello world!");
assertEquals("Hello world!", first.getValue());
assertEquals("Hello world!", second.getValue());
}
/**
* 构造方法代理,需要有一个newInstance方法,并且该方法返回object的接口
* @throws Exception
*/
@Test
public void testConstructorDelegate() throws Exception {
SampleBeanConstructorDelegate constructorDelegate = (SampleBeanConstructorDelegate) ConstructorDelegate
.create(SampleClass.class, SampleBeanConstructorDelegate.class);
//通过接口的newInstance返回实例
SampleClass bean = (SampleClass) constructorDelegate.newInstance();
assertEquals(true, SampleClass.class.isAssignableFrom(bean.getClass()));
}
/**
* 排序器,声称比jdk的默认排序器速度快
* @throws Exception
*/
@Test
public void testParallelSorter() throws Exception {
Integer[][] value = {
{4, 3, 9, 0},
{2, 1, 6, 0}
};
ParallelSorter.create(value).mergeSort(0);
for(Integer[] row : value) {
int former = -1;
for(int val : row) {
assertEquals(true, former < val);
former = val;
}
}
}
/**
* Fastclass声称比jdk原始的反射速度快,目前不推荐使用
* @throws Exception
*/
@Test
public void testFastClass() throws Exception {
FastClass fastClass = FastClass.create(SampleClass.class);
FastMethod fastMethod = fastClass.getMethod(SampleClass.class.getMethod("getValue"));
SampleClass myBean = new SampleClass();
myBean.setValue("Hello cglib!");
assertEquals("Hello cglib!", fastMethod.invoke(myBean, new Object[0]));
}
}
cglib基于ASM做了一层封装使得开发变得简单,但是性能上肯定是比asm差一些的,asm的api全是基于字节码层面的,如果对jvm的字节码不熟悉很难去使用。