cglib大名在java界如雷贯耳,众多优秀的开源项目均使用其来实现各自的功能(spring aop,hibernate等等),这里主要简单介绍一下cglib的使用,对比一下java原生的proxy还有javaassist.
说到cglib第一印象就是动态代理(啥是动态代理?请百度<设计模式>),没错,这是它牛逼的功能之一,
使用cglib构建动态代理核心类就是Enhancer,作用如其名:增强.它能够对目标类的方法进行增强.上代码:
/**
* Created by wally on 3/1/18.
*/
public abstract class Animal {
private String name;
public Animal() {
}
public Animal(String name) {
this.name = name;
}
public abstract void eat();
public void live(){
System.out.println("i'm " + name);
eat();
}
}
public class Duck extends Animal {
public Duck() {
}
public Duck(String name) {
super(name);
}
@Override
public void eat() {
System.out.println("i'm eat fish!");
}
}
/**
* Created by wally on 3/1/18.
*/
public class ProxyCreator {
public static <T> T createProxy(Class<T> target,T instance){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target);
CallbackHelper callbackHelper = new CallbackHelper(Duck.class,new Class[0]) {
@Override
protected Object getCallback(Method method) {
if(method.getName().equals("live")){
return NoOp.INSTANCE;
}
return new DuckProxy();
}
};
enhancer.setCallbackFilter(callbackHelper);
enhancer.setCallbacks(callbackHelper.getCallbacks());
return (T)enhancer.create(new Class[]{String.class},new String[]{"唐老鸭"});
}
}
/**
* Created by wally on 3/1/18.
*/
public class Starter {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Duck duck = ProxyCreator.createProxy(Duck.class,null);
duck.live();
}
}
上述栗子的输出:
i'm 唐老鸭
say gua gua!
i'm eat fish!
可以看到Duck类的eat行为发生变化了。在不调整原有代码的基础上改变原有对象的行为(严格意义上原有行为并没有变,只是包装了一层,是的,装饰者模式可以看做一种特殊的代理!)。这有什么用呢,我们来看一下大家都是怎么用的。
在hibernate中,使用cglib对bean进行代理,从而实现延迟加载,我们会发现,hibernate正真执行sql的时候往往不是我们调用查询方法的时候,而是在调用查询结果的时候采取真正执行。
在spring中,当我们通过注解@EnableAspectJAutoProxy开启aop时,可以指定是使用java原生proxy还是使用cglib,通过设置proxyTargetClass=true/false(使用cglib/使用java proxy).
通过代理,可以将业务逻辑与通用逻辑解耦,例如日志打印,数据库链接等等。
cglib除了强大的动态代理,还有一个功能:动态生成对象
/**
* Created by wally on 3/1/18.
*/
public class Beangenerator {
public static Object generateBean(Map<String, Class<?>> params, Class<?> superClass) {
BeanGenerator generator = new BeanGenerator();
if (params != null && params.size() != 0) {
params.forEach(generator::addProperty);
}
if (superClass != null)
generator.setSuperclass(superClass);
return generator.create();
}
}
cglib是对ASM的封装,ASM是一个字节码生成工具,所以cglib可以实现动态字节码生成,上面栗子通过BeanGenerator实例来生成指定属性的对象,该对象会自带setter和getter方法,可以通过反射获取。
值得一提的是,由于cglib是生成字节码,我们知道java的类信息释放在permanent edition中的,通过cglib生成的类信息也不例外,所以在使用cglib生成代理类或者bean时,需要注意,平凡的创建有可能导致pem 区的oom。
java proxy对比cglib:
java proxy由于是java自身支持的,在生成代理类时速度比cglib快,但是cglib是通过插入字节码来实现代理的,在调用速度上cglib要比java proxy快
在功能上,java proxy仅仅支持接口级别的代理,而cglib没有这个限制,目标类可以是接口可以是普通类,并且可以精确到方法级别(上面的栗子可以看出)。
来源:oschina
链接:https://my.oschina.net/u/4395983/blog/4247557