Cglib实现

CGLIB使用

what

CGLIB: 基于 ASM的字节码框架.

why

1.如果要代理的类为一个普通类、没有实现接口,只能使用CGLIB.
2.CGLIB底层使用了ASM.

demo

MyCommons/T01cglib

生成的cglib包下
PersonService$$EnhancerByCGLIB$$2d683b90$$FastClassByCGLIB$$8b3052f3.class

// cglib生成的代理类,继承了PersonService类
PersonService$$EnhancerByCGLIB$$2d683b90.class

PersonService$$FastClassByCGLIB$$edd83f4d.class

包结构

net.sf.cglib.beans
    Java bean 相关的工具类
net.sf.cglib.core
    底层字节码操作相关的类
    大多数与 ASM 相关
net.sf.cglib.proxy
    代理创建和方法拦截相关的类
net.sf.cglib.reflect
    反射相关的类
net.sf.cglib.transform
    编译和运行时, 类文件转换相关的类
net.sf.cglib.util
    集合排序工具相关类

缓存

cglib 通过缓存已经生成的类, 提升效率.
生成类的缓存是按照 ClassLoader 来划分的.

AbstractClassGenerator 类
    create()
        模板方法, 定义生成类的过程
    generateClass(ClassVisitor v)
        子类实现, 用于生成所需的类

class name 生成策略

命名策略
class generator 必须继承 AbstractClassGenerator , 然后实现抽象方法 generateClass(),
generateClass 方法用来生成 class , class name 的生成也应该是在这个方法中.

在每个 generateClass 方法中, 当调用 ClassEmitter 的 begin_class 方法时都要求提供一个入参 class internal name.
这时会调用 AbstractClassGenerator 的 getClassName() 来生成一个可用的 class internal name.

final protected String getClassName() {
    if (className == null)
        className = getClassName(getClassLoader());
    return className;
}

private String getClassName(final ClassLoader loader) {
    final Set nameCache = getClassNameCache(loader);
    return namingPolicy.getClassName(namePrefix, source.name, key, new Predicate() {
        public boolean evaluate(Object arg) {
            return nameCache.contains(arg);
        }
    });
}

private Set getClassNameCache(ClassLoader loader) {
    return (Set)((Map)source.cache.get(loader)).get(NAME_KEY);
}

getClassName 首先根据 classloader 和 NAME_KEY 来获取已经生成的类名的列表.
命名策略是封装在 NamingPolicy 中的 getClassName 方法中的. 用户可以根据自己的实际需求通过实现接口 NamingPolicy 来定制命名策略.
Cglib 提供了一个默认的命名策略 DefaultNamingPolicy.DefaultNamingPolicy 同样实现了 NamingPolicy 接口.
这部分代码比较简单, 我们可以分析得出, 默认的命名策略为
被代理 class name + "$$" + class generator name + "ByCGLIB" + "$$" + key 的 hashcode

如果命名冲突的话, 会在上面产生的类名后面 + "_"+index(index>=2).

Class 生成策略

cglib 中生成类的工作是由 AbstractClassGenerator 的 create 方法使用相应的生成策略完成.

// 默认生成类的策略
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
byte[] b = strategy.generate(this);

GeneratorStrategy 是一个接口, 它负责调用 ClassGenerator 的 generateClass 方法来生成类.
DefaultGeneratorStrategy 是 cglib 提供的一个默认的生成策略.

public class DefaultGeneratorStrategy implements GeneratorStrategy {
    public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy();

    public byte[] generate(ClassGenerator cg) throws Exception {
        DebuggingClassWriter cw = getClassVisitor();
        transform(cg).generateClass(cw);
        return transform(cw.toByteArray());
    }

    protected DebuggingClassWriter getClassVisitor() throws Exception {
      return new DebuggingClassWriter(ClassWriter.COMPUTE_MAXS);
    }

    ... ...

    protected byte[] transform(byte[] b) throws Exception {
        return b;
    }

    protected ClassGenerator transform(ClassGenerator cg) throws Exception {
        return cg;
    }
}

DefaultGeneratorStrategy 实现了 ClassGenerator 接口, 并提供两个 transform 方法.
用户可以通过继承 DefaultGeneratorStrategy 并重写相关的方法来检查或者修改生成类.

类生成策略, 用户可以通过实现 GeneratorStrategy 接口来自定义生成策略, 并使用 AbstractClassGenerator 的 setStrategy 方法来设置自定义策略.

cglib 动态代理原理

cglib 动态代理 demo

  1. 创建 Enhancer 实例
  2. 通过 setSuperclass 方法来设置目标类
  3. 通过 setCallback 方法来设置拦截对象
    4.create 方法生成 Target 的代理类, 并返回代理类的实例
// 1. 创建 Enhancer 实例
Enhancer enhancer = new Enhancer();
// 2. 将目标类设置为父类, 因为 cglib 基于父类 生成代理子类
enhancer.setSuperclass(PersonService.class);
// 3. 设置回调, 也就是我们的拦截处理
enhancer.setCallback(new CglibProxyInterceptor());
// 4. 创建代理类, 并返回代理类的实例
PersonService proxy = (PersonService) enhancer.create();

// 5. 调用代理类的方法
proxy.setPerson();
proxy.getPerson("1");

自定义拦截处理器如下:

public class CglibProxyInterceptor implements MethodInterceptor {
    /**
     * @param sub cglib 生成的代理对象
     * @param method 被代理对象方法
     * @param objects 方法入参
     * @param methodProxy 代理方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行前...");
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("执行后...");
        return object;
    }
}

代理类

FastClass 机制

Jdk 动态代理的拦截对象是通过反射的机制来调用被拦截方法的, 反射的效率比较低.
cglib 采用了 FastClass 的机制来实现对被拦截方法的调用.
FastClass 机制就是对一个类的方法建立索引, 通过索引来直接调用相应的方法.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FlyingZCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值