News:三分天注定,七分靠打拼,爱拼才会赢!致力打造专业IT博客。如果你对本博客有任何意见或建议请联系作者,邮箱:blog@caokuan.cn

CGLib 动态代理

逝水无痕 532 0 条

CGLib 是一个高性能的类库,可以为没有实现接口的类提供代理,是 Java 动态代理的一个补充,目前广泛应用在 Spring、Hibernate 等框架中。我在上一篇文章中详细讲解了 Java 动态代理的实现方法和原理,在这篇文章中将主要介绍 CGLib 动态代理的使用方法。

cglib动态代理.jpg

CGLib 原理

CGLib 原理:动态生成一个被代理类的子类,子类重写了被代理的类的所有不是 final 的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用反射的 Java 动态代理要快。

CGLib 底层:使用字节码处理框架 ASM ,来转换字节码并生成新的类。不鼓励直接使用 ASM ,因为它要求你必须对 JVM 内部结构包括 class 文件的格式和指令集都很熟悉。

CGLib 不足:对于 final 修饰的方法无法代理。

与 Java 动态代理的比较

1、java 动态代理生成的代理类和委托类实现了相同的接口,而且委托类必须要实现接口
2、cglib 动态代理中生成的字节码更加复杂,委托类不需要实现任何借口,生成的代理类是委托类的子类,且不能处理被 final 关键字修饰的方法
3、java 动态代理采用反射机制调用委托类的方法,cglib 采用类似索引的方式直接调用委托类方法

CGLib 简单应用示例

引入 maven 依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>3.2.6</version>
</dependency>

CGLib 需要使用 Enhancer 和 MethodInterceptor 来实现动态代理。下面是代码示例:

1、被代理类:普通类即可,不需要实现任何接口

public class Subject {

    public String sayHello() {
        System.out.println("hello");
        return "hello";
    }
    
    public void sayWorld() {
        System.out.println("world");
    }
    
    public void sayHelloWorld() {
        System.out.println("hello world");
    }
}

2、MethodInterceptor 接口实现类:完成功能增强

public class SubjectInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("前置增强处理");
        Object r = proxy.invokeSuper(obj, args); // 执行父类的方法
        System.out.println("后置增强处理");
        return r;
    }
}

3、测试类

public class TestDemo01 {
    
    public static void main(String[] args) {
        Enhancer en = new Enhancer();
        en.setSuperclass(Subject.class);
        en.setCallback(new SubjectInterceptor());
        Subject sub = (Subject) en.create();
        sub.sayHello();
    }
}

输出结果:

前置增强处理
hello
后置增强处理

CGLib MethodInterceptor 应用示例

1、被代理类(同上)

public class Subject {

    public String sayHello() {
        System.out.println("hello");
        return "hello";
    }
    
    public void sayWorld() {
        System.out.println("world");
    }
    
    public void sayHelloWorld() {
        System.out.println("hello world");
    }
}

2、第一个 MethodInterceptor

public class SubjectInterceptor1 implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("SubjectInterceptor1-前置增强");
        Object r = proxy.invokeSuper(obj, args);  // 执行父类的方法
        System.out.println("SubjectInterceptor1-后置增强");
        return r;
    }
}

3、第二个 MethodInterceptor

public class SubjectInterceptor2 implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("SubjectInterceptor2-前置增强");
        Object r = proxy.invokeSuper(obj, args);  // 执行父类的方法
        System.out.println("SubjectInterceptor2-后置增强");
        return r;
    }
}

4、第三个 MethodInterceptor

public class SubjectInterceptor3 implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("SubjectInterceptor3-前置增强");
        Object r = proxy.invokeSuper(obj, args);  // 执行父类的方法
        System.out.println("SubjectInterceptor3-后置增强");
        return r;
    }
}

5、CallbackFilter :返回的数值为在 Enhancer 传入的 Callback[] 数组中的 MethodInterceptor 位置索引

public class SubjectCallbackFilter implements CallbackFilter {

    @Override
    public int accept(Method method) {
        String name = method.getName();
        if (name.equals("sayHello")) {
            return 0; // 表示 Callback[] 数组中的索引值0
        } else if (name.equals("sayWorld")) {
            return 1; // 表示 Callback[] 数组中的索引值1
        } else if (name.equals("sayHelloWorld")) {
            return 2; // 表示 Callback[] 数组中的索引值2
        }
        return 3; // 表示 Callback[] 数组中的索引值3
    }
}

6、测试类

public class TestDemo02 {

    public static void main(String[] args) {
        
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Subject.class);
        enhancer.setCallbackFilter(new SubjectCallbackFilter());
        Callback[] callbacks = new Callback[] {
                new SubjectInterceptor1(),
                new SubjectInterceptor2(),
                new SubjectInterceptor3(),
                NoOp.INSTANCE  // 表示不进行增强处理
        };
        enhancer.setCallbacks(callbacks);
        Subject subject = (Subject) enhancer.create();
        subject.sayHello();
        subject.sayWorld();
        subject.sayHelloWorld();
        subject.hashCode(); // 在 CallbackFilter 中返回3,对应数组中的 NoOp.INSTANCE ,所以不会有增强处理
    }
}

输出结果:

SubjectInterceptor1-前置增强
hello
SubjectInterceptor1-后置增强
SubjectInterceptor2-前置增强
world
SubjectInterceptor2-后置增强
SubjectInterceptor3-前置增强
hello world
SubjectInterceptor3-后置增强

以上仅是 CGLib 用法的一小部分,还有其他很多用法没有列举,比如懒加载、接口生成器等等,有兴趣的同学可以自己去钻研学习。

与本文相关的文章

发表我的评论
icon_mrgreen.gificon_neutral.gificon_twisted.gificon_arrow.gificon_eek.gificon_smile.gificon_confused.gificon_cool.gificon_evil.gificon_biggrin.gificon_idea.gificon_redface.gificon_razz.gificon_rolleyes.gificon_wink.gificon_cry.gificon_surprised.gificon_lol.gificon_mad.gificon_sad.gificon_exclaim.gificon_question.gif

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址