CGLIB-API学习

转载自:https://blog.csdn.net/it_freshman/article/details/81223524

CGLIB是一个功能强大的高性能代码生成库。
它被广泛应用于许多AOP的框架使用,例如Spring AOP和dynaop。
Hibernate使用CGLIB来代理单端single-ended(多对一和一对一)关联。
CGLIB底层是基于ASM实现的。

通过maven引入依赖,来使用cglib:

    <!-- https://mvnrepository.com/artifact/cglib/cglib -->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2.2</version>
    </dependency>

cglib的包结构如下:

net.sf.cglib.core :底层字节码处理类,他们中的大多数都与ASM有关。
net.sf.cglib.transform :用于class文件运行时转换或编译时转换
net.sf.cglib.proxy :代理的创建和方法拦截相关。
net.sf.cglib.reflect :  该包中的类用于快速反射,并提供了C#风格的委托。
net.sf.cglib.util :集合排序工具类
net.sf.cglib.beans :javabean相关工具

Proxy APIs

API
cglib可以为没有implement interfacesnon-final类生成代理类。它比JDK动态代理方法更快。

net.sf.cglib.proxy.Callback Interface是一个标记接口。
所有被net.sf.cglib.proxy.Enhancer class调用的类都要事先CallBack接口。
net.sf.cglib.proxy.MethodInterceptor是所有CallBack中最通用的回调类型。
public interface MethodInterceptor extends Callback {
    /**
     *
     * @param proxyObject 代理对象
     * @param method 被代理方法
     * @param objects 参数
     * @param methodProxy 代理后方法
     * @return
     * @throws Throwable
     */
    Object Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable ;
}

net.sf.cglib.proxy.MethodInterceptor能够满足任何的拦截需要。但对有些情况下overkill(杀鸡焉用宰牛刀)了。为了简化和提高性能,CGLIB包提供了一些专门的回调(callback)类型:

    net.sf.cglib.proxy.FixedValue :为了提升性能,强制特定方法返回固定值
    net.sf.cglib.proxy.NoOp :nothing,直接调用父类方法。
    net.sf.cglib.proxy.LazyLoader : 当实际的对象需要延迟装载时,可以使用LazyLoader回调。在不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化。在第一次访问之时会初始化,然后之后的操作都不会触发。
    net.sf.cglib.proxy.Dispatcher:Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,Dispatcher .loadObject() 也总要被调用.

public interface Dispatcher extends Callback {
    Object loadObject() throws Exception;
}

net.sf.cglib.proxy.ProxyRefDispatcher : 类似Dispatcher,不同的是它可以把代理对象作为装载对象方法的一个参数传递。

public interface ProxyRefDispatcher extends Callback {
    Object loadObject(Object o) throws Exception;
}

User.eat()方法添加记录时间的功能

public class User {
    public void eat(String food){
        System.out.printf("i am eat %s now.....\n",food);
    }
}

public class TimeMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("loging start...");

        //这里不能使用 method.invoke(),会出现死循环
        Object result = methodProxy.invokeSuper(proxyObject,args);

        System.out.printf("%s() cost :%d ms\n",method.getName(),(System.currentTimeMillis() - start));

        return result;
    }
}

测试用例:

    @Test
    public void test02(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(User.class);//设置代理类,只能是non-final方法
        enhancer.setCallback(new TimeMethodInterceptor());

        User proxy = (User) enhancer.create();
        //只能是non-final方法,否则代理将失效,直接调用原逻辑
        proxy.eat("banana");

        //打印代理类名称
        System.out.println(proxy.getClass().getName());
    }

执行结果:

loging start...
i am eat banana now.....
eat() cost :38 ms
cn.jhs.cglib.User$$EnhancerByCGLIB$$cbe988a

源码解析
如何查看cglib动态代理产生的类呢?我们可以在生成代理类之前增加一个系统变量,即可在工程根目录/proxy_out获得产生的代理类.

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "proxy_out");

查看代理类User$$EnhancerByCGLIB$$cbe988a

public class User$$EnhancerByCGLIB$$cbe988a extends User implements Factory {

    final void CGLIB$eat$0(String var1) {
        super.eat(var1);
    }

    public final void eat(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if(this.CGLIB$CALLBACK_0 == null) {    
            /*
            * 1.绑定callback
            *  
            * var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
            */  
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if(var10000 != null) {
           /**
            * 2.直接调用MethodInterceptor的interceptor方法
            *
            * CGLIB$eat$0$Method = ReflectUtils.findMethods(new String[]{"eat", "(Ljava/lang/String;)V"}, (var1 = Class.forName("cn.jhs.cglib.User")).getDeclaredMethods())
            * CGLIB$eat$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "eat", "CGLIB$eat$0");
            */
            var10000.intercept(this, CGLIB$eat$0$Method, new Object[]{var1}, CGLIB$eat$0$Proxy);
        } else {
            super.eat(var1);
        }
    }

}

eat(String var1)方法可知,最终调用TimeMethodInterceptor.intercept()然后调用方法:

//这里不能使用 method.invoke(),会出现死循环
Object result = methodProxy.invokeSuper(proxyObject,args);

查看MethodProxy.invokeSuper()方法:

查看User$$EnhancerByCGLIB$$cbe988a$$FastClassByCGLIB$$d80fe27c.invoke()从上图可知参数为(18,User

EnhancerByCGLIB

cbe988a,”banana”)

 public class User$$EnhancerByCGLIB$$cbe988a$$FastClassByCGLIB$$d80fe27c extends FastClass {

        public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        cbe988a var10000 = (cbe988a)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
           //...........省略
            case 18:
                //var1=18,执行此行逻辑
                var10000.CGLIB$eat$0((String)var3[0]);
                return null;
            case 19:
                return cbe988a.CGLIB$findMethodProxy((Signature)var3[0]);
            //...........省略
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
}

CallbackFilter
net.sf.cglib.proxy.CallbackFilter可以有选择的对一些方法使用回调。当Enhancer.setCallbacks(Callback[])设置多个callback时,必须设置CallbackFilter来确保一个代理类只能接受一个拦截。
如果未设置,会报错:java.lang.IllegalStateException: Multiple callback types possible but no filter specified

@Test
   public void test03(){
       MethodInterceptor timeMethodInterceptor = new TimeMethodInterceptor();
       MethodInterceptor interceptor2 = (proxyObject, method, args,methodProxy) ->{
           System.out.println("interceptor2");
           return methodProxy.invokeSuper(proxyObject,args);
       };

       Enhancer enhancer = new Enhancer();
       enhancer.setSuperclass(User.class);//设置代理类,只能是non-final方法

       //设置多个Callback
       enhancer.setCallbacks(new Callback[]{timeMethodInterceptor,interceptor2});

       //设置CallbackFilter
       enhancer.setCallbackFilter((method) ->{
           String methodName = method.getName();
           if ("eat".equals(methodName)) {
               return 1; // eat()方法使用callbacks[1]对象拦截。
           }
           return 0;   //其他方法使用callbacks[0]对象拦截。
       });

       User proxy = (User) enhancer.create();
       //只能是non-final方法,否则代理将失效,直接调用原逻辑
       proxy.eat("banana");
   }

Mixin
Minix将多个对象&接口绑定到一个单独的对象上,变相的实现了java的多继承,其实依旧是implements 接口s

public abstract class Mixin {

    /**
     * delegates必须都implements Interfaces;
     **/
     public static Mixin create(Object[] delegates) {
        Mixin.Generator gen = new Mixin.Generator();
        gen.setDelegates(delegates);
        return gen.create();
    }

    /**
     * delegates[0]实现的接口必须包含interfaces[0]
     * delegates[....]实现的接口必须包含interfaces[....]
     * delegates[n]实现的接口必须包含interfaces[n]
     */
    public static Mixin create(Class[] interfaces, Object[] delegates) {
        Mixin.Generator gen = new Mixin.Generator();
        gen.setClasses(interfaces);
        gen.setDelegates(delegates);
        return gen.create();
    }
}

Beans APIs

BeanCopier
cglib提供的能够从一个bean复制到另一个bean中通过getter,setter复制,必须提供getter,setter方法。

public abstract class BeanCopier {
    /**
     *  source : 源头,即提供copy信息的class
      *  target : 目标,即需要cpoy的class
      *  useConverter 是否强转换标识,如果强制转换需要在copy()时加入Converter参数
      */
     public static BeanCopier create(Class source, Class target, boolean useConverter) {
       BeanCopier.Generator gen = new BeanCopier.Generator();
        gen.setSource(source);
        gen.setTarget(target);
        gen.setUseConverter(useConverter);
        return gen.create();
    }

    public abstract void copy(Object var1, Object var2, Converter var3);

    //BeanCopier 默认实现的子类
    public static class Generator extends AbstractClassGenerator {
    }
}

假设有U1,U2,现将U1实例source的属性copy给U2对象target

class U1{
    private int age;
    private String name
    //getter,setter
}

class U2{
    private Date age;
    private String name;
    private double sale;
    //getter,setter
}

测试

  @Test
   public void test05_BeanCopier() {
       //构建BeanCopier,并copy对象的属性值。
       Class sourceClazz = U1.class;
       Class targetClazz = U2.class;

       BeanCopier copier = BeanCopier.create(sourceClazz, targetClazz, false);
       U1 source = new U1(1,null);
       U2 target = new U2(new Date(),"u2",999.99);
       copier.copy(source, target, null);
       System.out.println(source);
       System.out.println(target);
   }

执行结果age由于类型不同没有覆盖

U1{age=1, name='null'}
U2{age=Thu Jul 26 22:33:06 CST 2018, name='null', sale=999.99}

BeanGenerator

    @Test
    public void test05_BeanGenerator(){
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "proxy_out");

        BeanGenerator generator = new BeanGenerator();
        generator.addProperty("age", int.class);
        generator.addProperty("name", String.class);
        //设置父类为java.util.Vector
        generator.setSuperclass(java.util.Vector.class);
        Object obj = generator.create();

        System.out.println(obj.getClass().getName());
    }

生成/package为 $java.util下的$java.util.Vector$$BeanGeneratorByCGLIB$$5a78c5e0,如下:

package $java.util;

import java.util.Vector;

public class Vector$$BeanGeneratorByCGLIB$$5a78c5e0 extends Vector {
    private String $cglib_prop_name;
    private int $cglib_prop_age;

    public Vector$$BeanGeneratorByCGLIB$$5a78c5e0() {
    }

    public String getName() {
        return this.$cglib_prop_name;
    }

    public void setName(String var1) {
        this.$cglib_prop_name = var1;
    }

    public int getAge() {
        return this.$cglib_prop_age;
    }

    public void setAge(int var1) {
        this.$cglib_prop_age = var1;
    }

BeanMap

//实现了java.util.Map接口
public abstract class BeanMap implements Map {
    public static BeanMap create(Object bean) {
        BeanMap.Generator gen = new BeanMap.Generator();
        gen.setBean(bean);
        return gen.create();
    }

}

BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map.

这里介绍一个关于Cglib的工具类,以后直接使用
CglibBean bean = new CglibBean(new HashMap());调用即可。

public class CglibBean {
    /**
     * 实体Object
     */
    public Object object = null;

    /**
     * 属性map
     */
    public BeanMap beanMap = null;


    public CglibBean() {
        super();
    }

    @SuppressWarnings("unchecked")
    public CglibBean(Map propertyMap) {
        this.object = generateBean(propertyMap);
        this.beanMap = BeanMap.create(this.object);
    }

    /**
     * 给bean属性赋值
     * @param property 属性名
     * @param value 值
     */
    public void setValue(String property, Object value) {
        beanMap.put(property, value);
    }

    /**
     * 通过属性名得到属性值
     * @param property 属性名
     * @return 值
     */
    public Object getValue(String property) {
        return beanMap.get(property);
    }

    /**
     * 得到该实体bean对象
     * @return
     */
    public Object getObject() {
        return this.object;
    }

    @SuppressWarnings("unchecked")
    private Object generateBean(Map propertyMap) {
        BeanGenerator generator = new BeanGenerator();
        Set keySet = propertyMap.keySet();
        for (Iterator i = keySet.iterator(); i.hasNext();) {
            String key = (String) i.next();
            generator.addProperty(key, (Class) propertyMap.get(key));
        }
//      generator.setSuperclass(java.util.Vector.class);
        return generator.create();
    }

}

BulkBean
BulkBean类似于BeanCopier,它将BeanCopier.copy()分解为两个动作:getPropertyValues和setPropertyValues()

public abstract class BulkBean {

    public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) {
        BulkBean.Generator gen = new BulkBean.Generator();
        gen.setTarget(target);
        gen.setGetters(getters);
        gen.setSetters(setters);
        gen.setTypes(types);
        return gen.create();
    }   


    public abstract void setPropertyValues(Object var1, Object[] var2);

    public Object[] getPropertyValues(Object bean) {
        Object[] values = new Object[this.getters.length];
        this.getPropertyValues(bean, values);
        return values;
    }    

}

例:

 public void test06_BulkBean(){
       Class target = U1.class;
       String[] getters = new String[]{"getAge","getName"};
       String[] setters = new String[]{"setAge","setName"};
       Class[] types = new Class[]{int.class, String.class};
       BulkBean bulkBean = BulkBean.create(U1.class, getters, setters, types);
       U1 bean = new U1(1,"trump");
       Object[] propertyValues = bulkBean.getPropertyValues(bean);
       System.out.println(Arrays.asList(propertyValues));

       bulkBean.setPropertyValues(bean,new Object[]{22,null}); //[1, trump]
       System.out.println(Arrays.asList(bulkBean.getPropertyValues(bean))); //[22, null]
   }

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值