1. Enhancer 简介
enhancer 是`cglib`中使用最频繁的类。enhancer可以用来创建非接口级别的java代理(可以对类或方法进行动态代理
-
- enhancer.create(Object …) 方法可以创建父类的子类对象;
-
- enhancer.createClass() 方法可以创建父类的子类;
-
- 除了
构造器
,静态方法
和final方法
,父类的所有方法都可以被代理(包含父类的父类);
- 除了
2. enhancer 回调器介绍
1. FixValue 回调器
FixValue 回调器需要实现一个 loadObject
方法,该方法返回的结果将作为被代理方法的一致返回结果。
/**被代理类*/
public class SampleClass {
public String test(String input) {
return "Hello world!";
}
}
@Test
public void testFixedValue() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "Hello cglib!";
}
});
SampleClass proxy = (SampleClass) enhancer.create();
assertEquals("Hello cglib!", proxy.test(null));
}
2. InvocationHandler 调度器
InvocationHandler 回调器需要实现一个 invoke 方法,该方法可以在被代理方法调用时进行逻辑织入。
@Test
public void testInvocationHandler() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
return "Hello cglib!";
} else {
throw new RuntimeException("Do not know what to do.");
}
}
});
SampleClass proxy = (SampleClass) enhancer.create();
assertEquals("Hello cglib!", proxy.test(null));
assertNotEquals("Hello cglib!", proxy.toString());
}
- InvocationHandler 实例重写了方法的调用逻辑。当一个实例的对象方法被外部调用时,将会调用
invoke
方法(包括invoke方法本身)。因此,需要注意不能主动调用 invoke 方法,调用该方法会导致无限死循环。(invoke仅仅是调用逻辑,不是拦截逻辑)
3. MethodInterceptor(方法拦截器)
MethodInterceptor 拦截器需要实现 intercept 方法,该方法可以完全控制拦截策略,因此不存在死循环调用风险
@Test
public void testMethodInterceptor() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
return "Hello cglib!";
} else {
return proxy.invokeSuper(obj, args);
}
}
});
SampleClass proxy = (SampleClass) enhancer.create();
assertEquals("Hello cglib!", proxy.test(null));
assertNotEquals("Hello cglib!", proxy.toString());
proxy.hashCode(); // Does not throw an exception or result in an endless loop.
# }
4. LazyLoader(延迟加载器)
LazyLoader 延迟加载被代理对象,调用时产生一个父类的实例。
5. Dispatcher(调用分发器)
Disptcher 可以分发被调方法到具体实例。实例改变无需引用更新,需要注意代理创建所用的构造函数必须兼容所有被代理实例。
6. ProxyRefDispatcher(调用分发器-带代理引用承载功能)
ProxyRefDispatcher和Disptcher
类似,但是可以承载具体被代理对象的引用。
7. NoOp(直接方法委托)
将对方法的调用直接委托到父类的实现中去
3. 代理拦截器介绍
**将方法和对应的 callback
(回调器) 关联起来。代理拦截器通过 enhancer.setCallbackFilter 实现。
cglib
提供了 CallbackHelper
类用于简化过滤器的实现。**
public void testCallbackFilter() throws Exception {
Enhancer enhancer = new Enhancer();
CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
@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.
}
}
};
enhancer.setSuperclass(MyClass.class);
enhancer.setCallbackFilter(callbackHelper);
enhancer.setCallbacks(callbackHelper.getCallbacks());
SampleClass proxy = (SampleClass) enhancer.create();
assertEquals("Hello cglib!", proxy.test(null));
assertNotEquals("Hello cglib!", proxy.toString());
proxy.hashCode(); // Does not throw an exception or result in an endless loop.
}
4. cglib 代理工具类(不全)
1. ImmutableBean (不可变代理)
该代理工具可以确保被代理的对象不被改变
/**
* bean 样例定义
*/
public class SampleBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
/**
* 修改 ImmutableBean 代理的对象将会抛出 IllegalStateException 异常
*/
@Test(expected = IllegalStateException.class)
public void testImmutableBean() throws Exception {
SampleBean bean = new SampleBean();
bean.setValue("Hello world!");
SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean);
assertEquals("Hello world!", immutableBean.getValue());
bean.setValue("Hello world, again!");
assertEquals("Hello world, again!", immutableBean.getValue());
immutableBean.setValue("Hello cglib!"); // Causes exception.
}
2. BeanGenerator(bean生成器代理)
bean生成器代理主要应用于特定属性bean的创建
@Test
public void testBeanGenerator() throws Exception {
BeanGenerator beanGenerator = new BeanGenerator();
beanGenerator.addProperty("value", String.class);
Object myBean = beanGenerator.create();
Method setter = myBean.getClass().getMethod("setValue", String.class);
setter.invoke(myBean, "Hello cglib!");
Method getter = myBean.getClass().getMethod("getValue");
assertEquals("Hello cglib!", getter.invoke(myBean));
}
3. BeanCopier(bean复制器代理)
主要实现在不同类型bean之间进行属性赋值
/** 待赋值目标 */
public class OtherSampleBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
/**
* 将 SampleBean 实例的属性赋值到 OtherSampleBean 实例上去
*/
@Test
public void testBeanCopier() throws Exception {
/** false 参数指示 copy 方法不使用 第三方扩展的赋值方法 */
BeanCopier copier = BeanCopier.create(SampleBean.class, OtherSampleBean.class, false);
SampleBean bean = new SampleBean();
bean.setValue("Hello cglib!");
OtherSampleBean otherBean = new OtherSampleBean();
/** 第三个参数是自己扩展的赋值实现对象 */
copier.copy(bean, otherBean, null);
assertEquals("Hello cglib!", otherBean.getValue());
}
4. BulkBean(批处理bean代理)
将对bean的属性操作方式转换成数组成员的操作方式
@Test
public void testBulkBean() throws Exception {
BulkBean bulkBean = BulkBean.create(SampleBean.class,
new String[]{"getValue"},
new String[]{"setValue"},
new Class[]{String.class});
SampleBean bean = new SampleBean();
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());
}
5. BeanMap(映射表bean代理)
将bean的属性映射成 String-Object 形式的映射表
@Test
public void testBeanGenerator() throws Exception {
SampleBean bean = new SampleBean();
BeanMap map = BeanMap.create(bean);
bean.setValue("Hello cglib!");
assertEquals("Hello cglib", map.get("value"));
}
6. KeyFactory(键工厂)
KeyFactory 会自动实现正确的 equals 和 hashCode 方法, 保证其生成的对象可以用作 map|set 的主键。需要注意的是 KeyFactory 使用时需要定义一个 单方法接口, 该接口的唯一方法名称为 newInstance 且其返回值为 Object
public interface SampleKeyFactory {
Object newInstance(String first, int second);
}
@Test
public void testKeyFactory() throws Exception {
SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory.create(Key.class);
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)));
}
该文档是对cglib tutorial的总结,更全面的介绍请看原文