精讲23种设计模式-002:CGLIB底层实现的原理

1 CGLIB动态代理课程内容安排

课程内容

  1. 如何基于CGLIB实现动态代理
  2. CGLIB底层实现原理源码解读
  3. 为什么CGLIB效率会比Jdk动态代理效率高
  4. CGLIB的FastClass机制实现的原理

2 CGLIB与JDK动态代理之间的区别

动态代理模式
Jdk动态代理:实现InvocationHandler接口走invoke回调拦截,使用反射技术执行目标方法;实现接口的形式生成代理类
1.拼接java源代码
2.编译为class文件
3.读取class文件到内存中
采用java的反射机制执行目标方法

Cglib动态代理:基于字节码技术实现封装;采用继承模式生成代理类,底层基于Asm字节码技术生成代理类
1.生成class文件
2.读取class文件到内存中
采用fastClass索引机制执行目标方法

注:Cglib动态代理的效率比Jdk动态代理效率要高

3 使用CGLIB实现动态代理

引入maven依赖

<dependencies>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.12</version>
    </dependency>
</dependencies>

使用CGLIB实现动态代理

public interface MemberService {

    String addMember(String userName);
}
public class MemberServiceImpl implements MemberService {

    @Override
    public String addMember(String userName) {
        System.out.println("...目标方法...");
        return userName;
    }
}
public class CglibMethodInterceptor implements MethodInterceptor {

    /**
     * @param obj cglib生成好的代理类对象
     * @param method 目标方法
     * @param args 参数
     * @param proxy 代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("cglib动态代理执行开始>>>");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("cglib动态代理执行结束>>>");
        return result;
    }
}
public class Test001 {
    public static void main(String[] args) {
        
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MemberServiceImpl.class);
        enhancer.setCallback(new CglibMethodInterceptor());
        // 创建代理对象
        MemberServiceImpl memberServiceImpl = (MemberServiceImpl) enhancer.create();
        memberServiceImpl.addMember("mayikt");
    }
}

运行结果:
请添加图片描述

4 CGLIB代理生成的代理类源码分析

生成代理类class文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “D:\code”);
代理类class文件
请添加图片描述Ps:用jd-gui.exe反编译class文件有缺失,推荐jadx-gui进行反编译。

Cglib生成的子类核心代码

public class MemberServiceImpl$$EnhancerByCGLIB$$600aa7a2 extends MemberServiceImpl {
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Method CGLIB$addMember$0$Method;
    private static MethodProxy CGLIB$addMember$0$Proxy;


    static void CGLIB$STATICHOOK1() throws ClassNotFoundException {
        Class<?> cls = Class.forName("com.mayikt.service.impl.MemberServiceImpl$$EnhancerByCGLIB$$600aa7a2");
        Class<?> cls3 = Class.forName("com.mayikt.service.impl.MemberServiceImpl");
        CGLIB$addMember$0$Method = ReflectUtils.findMethods(new String[]{"addMember", "(Ljava/lang/String;)Ljava/lang/String;"}, cls3.getDeclaredMethods())[0];
        CGLIB$addMember$0$Proxy = MethodProxy.create(cls3, cls, "(Ljava/lang/String;)Ljava/lang/String;", "addMember", "CGLIB$addMember$0");
    }


    final String CGLIB$addMember$0(String paramString) {
        return super.addMember(paramString);
    }

    @Override
    public final String addMember(String paramString) {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null) {
            CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        try {
            if (tmp17_14 != null) {
                return (String) tmp17_14.intercept(this, CGLIB$addMember$0$Method, new Object[]{paramString}, CGLIB$addMember$0$Proxy);
            }
            return super.addMember(paramString);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return super.addMember(paramString);
    }

    private void CGLIB$BIND_CALLBACKS(MemberServiceImpl$$EnhancerByCGLIB$$600aa7a2 memberServiceImpl$$EnhancerByCGLIB$$600aa7a2) {
    }

    /**
     * 设置cglib的回调
     *
     * @param paramArrayOfCallback
     */
    public void setCallbacks(Callback paramArrayOfCallback) {
        this.CGLIB$CALLBACK_0 = ((MethodInterceptor) paramArrayOfCallback);
    }

    static {
        try {
            CGLIB$STATICHOOK1();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
public class Test002 {
    public static void main(String[] args) {

        MemberServiceImpl$$EnhancerByCGLIB$$600aa7a2 memberServiceImpl = new MemberServiceImpl$$EnhancerByCGLIB$$600aa7a2();
        memberServiceImpl.setCallbacks(new CglibMethodInterceptor());
        memberServiceImpl.addMember("mayikt");
    }
}

运行结果:
请添加图片描述

5 Jdk与Cglib动态代理的区别

Jdk动态代理:基于实现接口的形式生成代理类对象;使用java反射机制调用目标方法

  1. 需要拼接java源代码$proxy.java
  2. 需要将java源代码编译为class文件
  3. 采用类加载器读取class文件到程序中
  4. 采用java的反射机制执行目标方法

反射机制:method.invoke(target, args);

Cglib动态代理:基于继承目标对象生成代理类对象;(ASM)字节码技术

  1. 直接采用字节码技术生成class文件(无需编译过程)
  2. 采用类加载器读取class文件到程序中
  3. 采用FastClass机制调用到目标方法(比反射机制效率要高)

FastClass机制:memberService.add()
FastClass对目标对象中所有的方法生成一个索引的标记,直接根据索引调用到目标方法。

6 模拟手写调用FastClass类

fastClass索引生成:根据方法名称+参数类型生成签名,计算hash值

public class FastClass {

    public static int getIndex(String signature) {
        switch (signature.hashCode()) {
            case -1403673461:
                return 0;
        }
        return -1;
    }

    /**
     * @param i      索引值
     * @param obj    代理对象
     * @param objArr 参数值
     * @return
     */
    public static Object invoke(int i, Object obj, Object[] objArr) {
        // 走代理对象.addMember$0(); 通过super.addMember(str);真正执行目标对象的方法
        // 伪代码,正常是代理对象
        MemberServiceImpl memberService = (MemberServiceImpl) obj;
        switch (i) {
            case 0:
                return memberService.addMember(String.valueOf(objArr[0]));
        }
        return null;
    }
    
    public static void main(String[] args) {
        String name = "addMember(String)";
        System.out.println(name.hashCode());
        Object result = invoke(getIndex(name), new MemberServiceImpl(), new Object[]{"meite"});
        System.out.println(result);
    }

}

运行结果:
请添加图片描述
FastClass对代理对象和目标对象的每个方法设置一个索引值,通过索引值可以直接定位到具体方法进行调用。

7 FastClass机制底层源码解读

请添加图片描述
源码下载地址(mayikt_designPattern_2.rar):
链接:https://pan.baidu.com/s/1wWKZN1MbXICZVW1Vxtwe6A
提取码:fire

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值