Hello World

吞风吻雨葬落日 欺山赶海踏雪径

0%

cglib doc

cglib 文档

Wiki

https://github.com/cglib/cglib/wiki/Tutorial

http://mydailyjava.blogspot.com/2013/11/cglib-missing-manual.html

Code

https://github.com/cglib/cglib

other doc

http://agapple.iteye.com/blog/799827

Enhancer

Enhancer创建代理,基本流程

1
2
3
4
5
6
7
8
9
10
11
12
13
@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));
}

callback有很多类型,定义不同,作用也不同。

Callbacks

Dispatcher (net.sf.cglib.proxy)

FixedValue (net.sf.cglib.proxy)

锁定方法返回值,无论被代理类的方法返回什么值,回调方法都返回固定值。

InvocationHandler (net.sf.cglib.proxy)

LazyLoader (net.sf.cglib.proxy)

在使用延迟加载对象的时候触发一次回调。当创建对象代价很昂贵,且不知道会不会被用到的时使用比较合适。

官方解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
LazyLoader: 
Even though the LazyLoader's only method has the same method signature as FixedValue,
the LazyLoader is fundamentally different to the FixedValue interceptor.
The LazyLoader is actually supposed to return an instance of a subclass of the enhanced class.
This instance is requested only when a method is called on the enhanced object and then
stored for future invocations of the generated proxy.
This makes sense if your object is expensive in its creation
without knowing if the object will ever be used. Be aware that some
constructor of the enhanced class must be called both for the proxy
object and for the lazily loaded object. Thus, make sure that there is
another cheap (maybe protected) constructor available or use an interface
type for the proxy. You can choose the invoked constructed by supplying
arguments to Enhancer#create(Object...)

exp:

LoaderBean.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class LoaderBean {  
private String loaderName;
private int loaderValue;
private PropertyBean propertyBean;
public LoaderBean(){
this.loaderName="loaderNameA";
this.loaderValue=123;
this.propertyBean=createPropertyBean();
}
protected PropertyBean createPropertyBean(){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(PropertyBean.class);
return (PropertyBean)enhancer.create(PropertyBean.class,new ConcreteClassLazyLoader());
}

//setter/getter...
}

PropertyBean.java

1
2
3
4
5
6
public class PropertyBean {  
private String propertyName;
private int propertyValue;

//setter/getter
}

LazyLoader

1
2
3
4
5
6
7
8
9
public class ConcreteClassLazyLoader implements LazyLoader{  
public Object loadObject() throws Exception {
System.out.println("LazyLoader loadObject() ...");
PropertyBean bean=new PropertyBean();
bean.setPropertyName("lazy-load object propertyName!");
bean.setPropertyValue(11);
return bean;
}
}

main

1
2
3
4
5
6
7
8
9
LoaderBean loader=new LoaderBean();  
System.out.println(loader.getLoaderName());
System.out.println(loader.getLoaderValue());
PropertyBean propertyBean=loader.getPropertyBean();//访问延迟加载对象
System.out.println(propertyBean.getPropertyName());
System.out.println(propertyBean.getPropertyValue());
System.out.println("after...");
//当再次访问延迟加载对象时,就不会再执行回调了
System.out.println(propertyBean.getPropertyName());

输出结果:

1
2
3
4
5
6
7
loaderNameA  
123
LazyLoader loadObject() ...
lazy-load object propertyName!
11
after...
lazy-load object propertyName!

MethodInterceptor (net.sf.cglib.proxy)

NoOp (net.sf.cglib.proxy)

NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。

ProxyRefDispatcher (net.sf.cglib.proxy)

CallbackFilter

负责把执行的方法映射到对应的回调。
int accept(Method method);返回callback数组的序号。由setCallbacks(Callback[] callbacks)设置

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ConcreteClassNoInterface {  
public String getConcreteMethodA(String str){
System.out.println("ConcreteMethod A ... "+str);
return str;
}
public int getConcreteMethodB(int n){
System.out.println("ConcreteMethod B ... "+n);
return n+10;
}
public int getConcreteMethodFixedValue(int n){
System.out.println("getConcreteMethodFixedValue..."+n);
return n+10;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class ConcreteClassCallbackFilter implements CallbackFilter{  
public int accept(Method method) {
if("getConcreteMethodB".equals(method.getName())){
return 0;//Callback callbacks[0]
}else if("getConcreteMethodA".equals(method.getName())){
return 1;//Callback callbacks[1]
}else if("getConcreteMethodFixedValue".equals(method.getName())){
return 2;//Callback callbacks[2]
}
return 1;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Enhancer enhancer=new Enhancer();  
enhancer.setSuperclass(ConcreteClassNoInterface.class);
CallbackFilter filter=new ConcreteClassCallbackFilter();
enhancer.setCallbackFilter(filter);

Callback interceptor=new ConcreteClassInterceptor();//(1)
Callback noOp=NoOp.INSTANCE;//(2)
Callback fixedValue=new ConcreteClassFixedValue();//(3)
Callback[] callbacks=new Callback[]{interceptor,noOp,fixedValue};
enhancer.setCallbacks(callbacks);
ConcreteClassNoInterface proxyObject=(ConcreteClassNoInterface)enhancer.create();
System.out.println("*** NoOp Callback ***");
proxyObject.getConcreteMethodA("abcde");

System.out.println("*** MethodInterceptor Callback ***");
proxyObject.getConcreteMethodB(1);

System.out.println("*** FixedValue Callback ***");
int fixed1=proxyObject.getConcreteMethodFixedValue(128);
System.out.println("fixedValue1:"+fixed1);
int fixed2=proxyObject.getConcreteMethodFixedValue(256);
System.out.println("fixedValue2:"+fixed2);
1
2
3
4
5
6
7
8
public class ConcreteClassFixedValue implements FixedValue{  
public Object loadObject() throws Exception {
System.out.println("ConcreteClassFixedValue loadObject ...");
Object object=999;
return object;
}
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*** NoOp Callback ***  
ConcreteMethod A ... abcde

*** MethodInterceptor Callback ***
Before :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)
ConcreteMethod B ... 1
After :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)
ConcreteClassInterceptor end...

*** FixedValue Callback ***
ConcreteClassFixedValue loadObject ...
fixedValue1:999
ConcreteClassFixedValue loadObject ...
fixedValue2:999

getConcreteMethodA对应CallbackFilter中定义的索引1,在Callback[]数组中使用的过滤为NoOp,因此直接执行了被代理方法。
getConcreteMethodB对应CallbackFilter中定义的索引0,在Callback[]数组中使用的过滤为MethodInterceptor,因此执行了方法拦截器进行拦截。
getConcreteMethodFixedValue对应CallbackFilter中定义的索引2,在Callback[]数组中使用的过滤为FixedValue,因此2次赋值128和256的调用其结果均被锁定为返回999。

BeanCopier

不同bean相同属性名的互相拷贝,性能非常好。而且还支持不同类型的拷贝。
性能对比:http://www.iteye.com/topic/801577

  1. 避免每次进行BeanCopier.create创建对象,一般建议是通过static BeanCopier copier = BeanCopier.create()
  2. 合理使用converter。
  3. 应用场景:两个对象之间同名同属性的数据拷贝, 不能单独针对其中的几个属性单独拷贝