002:CGLIB底层实现的原理
1 CGLIB动态代理课程内容安排
课程内容
- 如何基于CGLIB实现动态代理
- CGLIB底层实现原理源码解读
- 为什么CGLIB效率会比Jdk动态代理效率高
- 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反射机制调用目标方法
- 需要拼接java源代码$proxy.java
- 需要将java源代码编译为class文件
- 采用类加载器读取class文件到程序中
- 采用java的反射机制执行目标方法
反射机制:method.invoke(target, args);
Cglib动态代理:基于继承目标对象生成代理类对象;(ASM)字节码技术
- 直接采用字节码技术生成class文件(无需编译过程)
- 采用类加载器读取class文件到程序中
- 采用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