cglib的使用

爱⌒轻易说出口 提交于 2021-02-12 04:45:56

   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没有这个限制,目标类可以是接口可以是普通类,并且可以精确到方法级别(上面的栗子可以看出)。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!