动态代理(二)---Cglib两种代理方式初探(非JDK代理)

本文探讨了Cglib动态代理的两种方式:继承非持有式代理和继承持有式代理。详细解释了创建代理的过程、调用方式及两者之间的区别。在非持有式代理中,代理类内部方法调用会被代理,而持有式代理则不会。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

曾经尝试在网上搜索 cglib的两种代理方式,搜到的结果基本全是讲动态代理的两种方式而非Cglib动态代理的两种方式。
按我的理解Cglib动态代理有两种,JDK的有一种,一共应该是三种动态代理才对。

本文灵感来源:在学习Spring框架的AOP模块时,在被代理方法(此处假设该方法的持有类为TestBean)里执行System.out.println(this.getClass());打印的结果是TestBean的类名,这与我期望结果有些偏差,我觉得应该是输出子类的类名。于是便对Cglib的代理模式和调用过程进行探究。

代理类通过执行回调类的intercept方法来对方法进行代理:

回调类需要实现的接口:MethodInterceptor
实现方法:intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy);
obj : 代理对象
method : 被代理对象的方法
args : 方法的参数
methodProxy : 代理对象的方法(与method的方法不同名,但是有对应关系,其方法实现与被代理对象对应方法的实现一致,而代理对象中与method同名的方法则被改写为:一部分判断逻辑和调用回调对象的intercept方法)

两种代理方式

1、继承非持有式代理
  1. 创建代理过程(无需额外创建被代理的对象)
    ① 创建Enhancer对象
    ② 用Enhancer对象设置代理类的父类(被代理类)
    ③ 创建回调对象(回调类实现 MethodInterceptor 接口)
    ④ 用Enhancer对象设置回调对象
    ⑤ 用Enhancer对象创建代理对象

  2. 调用方式
    在回调类的intercept函数中,执行:①前置输出 ②调用被代理对象的方法 ③后置输出
    注意点:② 中需使用 methodProxy 对象调用 invokeSuper 方法即:methodProxy.invokeSuper(obj,args); 参数名意义在上边

2、继承持有式代理
  1. 创建代理过程
    ① 创建被代理对象
    ② 创建回调对象,并将被代理对象存入回调对象的target变量中
    ③ 使用Enhancer的create(Class clazz, MethodInterceptor callBack)方法创建代理对象
  2. 调用方式
    在回调类的interpret函数中,执行:①前置输出 ②调用被代理对象的方法 ③后置输出
    注意点:② 中需要使用 method对象调用invoke方法,即:method.invoke(target,args);参数名意义在上边。此处也可执行methodProxy.invokeSuper(obj, args); 但如此调用target对象就变得无意义,而且代理方式同1 继承非持有式代理没有区别了

比较:

在代理方式1中,在客户端(main函数)中,生成的代理类调用的方法内部如果有调用该类的方法时,会对被调用的方法进行代理。
而在代理方式2中,不会。

示例(对上边比较的验证)

TestMain .java

package com.cglib.test;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.IOException;
import java.lang.reflect.Method;


public class TestMain {

    public static void main(String[] args) throws InterruptedException, IOException {


        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TestBean.class);
        enhancer.setCallback(new TBProxy());

        TestBean tb1 = (TestBean) enhancer.create();

        TestBean tb2 = (TestBean) Enhancer.create(TestBean.class, new TBProxyx(new TestBean()));

        tb1.print();
        System.out.println("\n\n\n");
        tb2.print();
    }

    // 被代理类
    static class TestBean {


        public void print() {

            System.out.println("i am printing something");
            t();
        }

        public void t() {
            System.out.println("=== im t() ===");
        }
    }
    // 代理方式1
    static class TBProxy implements MethodInterceptor {

        public TBProxy() {
        }

        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

            System.out.println("=============  start  ================");

            Object result = methodProxy.invokeSuper(obj, args);
            System.out.println("=============   end   ================");
            return null;
        }
    }
    // 代理方式2
    static class TBProxyx implements MethodInterceptor {

        public TBProxyx(Object obj) {

            this.target = obj;
        }

        Object target;

        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("=============  startaaa  ================");
            Object result = method.invoke(target, args);
            System.out.println("=============   endaaa   ================");
            return result;
        }
    }

}

输出:(第一种,t()函数的打印结果上下有前后置输出,而第二种没有。)

=============  start  ================
i am printing something
=============  start  ================
=== im t() ===
=============   end   ================
=============   end   ================




=============  startaaa  ================
i am printing something
=== im t() ===
=============   endaaa   ================

对生成类的分析见下一节内容

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值