JDK动态代理与CGLIB动态代理
目录
静态代理
只能代理某一特定类型的接口或类, 需要对于不同类型的接口或类写一个代理类
动态代理
JDK动态代理
可以代理不同类型的接口
cglib动态代理
可以代理不同类型的接口或类
代码示例
静态代理代码示例
/**
*
* 物流服务
* @author: haibin.tang
* @date: 2021/2/7
*/
public interface LogisticsService {
/**
* 发货
* @param logisticsNo 快递单号
*/
void delivery(String logisticsNo);
/**
* 签收
* @param logisticsNo 单号
*/
void signing(String logisticsNo);
}
/**
* 物流具体实现
* @author: haibin.tang
* @date: 2021/2/7
*/
public class LogisticsServiceImpl implements LogisticsService {
public void delivery(String logisticsNo) {
System.out.println("快递发货, 快递单号 -->> " + logisticsNo);
}
public void signing(String logisticsNo) {
System.out.println("快递签收, 快递单号 -->> " + logisticsNo);
}
}
/**
* @author: haibin.tang
* @date: 2021/2/7
*/
public class Main {
public static void main(String[] args) {
LogisticsProxy logisticsProxy = new LogisticsProxy();
logisticsProxy.delivery("P1001");
logisticsProxy.signing("P1000");
}
}
JDK动态代理代码示例
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public interface UserService {
String create(String name);
}
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public class UserServiceImpl implements UserService {
public String create(String name) {
System.out.println("创建用户 " + name);
return "create user ok";
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理类
* <br/>
* @author: haibin.tang
* @date: 2021/2/5
*/
public class JdkDynamicProxy implements InvocationHandler {
/**
* 真实对象
*/
private final Object target;
public JdkDynamicProxy(Object target) {
this.target = target;
}
/**
* 最终生成的目标代理类会调用该方法
* @param proxy 调用该方法的代理实例
* @param method 要调用的目标方法
* @param args 调用方法所需的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用开始" + target.getClass().getName() + "#" + method.getName());
return method.invoke(target, args);
}
}
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public class Main {
public static void main(String[] args) {
UserService userService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, new JdkDynamicProxy(new UserServiceImpl()));
System.out.println(userService.create("小明"));
System.out.println(userService.create("小红"));
saveProxyClass2Disk("e://UserService$Proxy.class", new Class[] {UserService.class});
}
/**
* 根据传入的class 生成代理类, 并且把class持久化到磁盘上
* @param path 持久化路径
* @param classes 动态生成的代理类需要实现的接口
*/
public static void saveProxyClass2Disk(String path, Class[] classes){
byte[] classFile = ProxyGenerator.generateProxyClass(path, classes);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path);
fos.write(classFile);
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
JDK动态代理原理
生成一个实现业务接口的class文件,内部通过委托给InvocationHanlder对象调用invoke方法
核心API
public interface InvocationHandler {
/**
* 代理方法,可以无侵入式的扩展真实方法调用前后的功能
* proxy: 生成的代理对象实例
* method: 调用真实类实例的方法
* args: 调用真实类实例方法所需的参数
* return: 真实方法的返回值,也可以返回其他的
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
/**
* loader: 类加载器, 用于加载生成的代理class
* interfaces: 生成的代理class需要实现的接口
* h: 自定义实现的InvocationHandler类型接口的类实例,用于生成的代理类实例调用该接口定义的invoke方法
*/
java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
生成的代理class文件
package e:..UserService$Proxy;
import com.nanxhs.proxy.jdk.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class class extends Proxy implements UserService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public class(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
/**
* UserService接口的方法
*/
public final String create(String var1) throws {
try {
// 调用invocationhanlder的invoke方法
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.nanxhs.proxy.jdk.UserService").getMethod("create", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
CGLIB动态代理代码示例
引入jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
代理接口示例
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public interface OrderService {
String create(String productName);
}
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public class OrderServiceImpl implements OrderService {
public String create(String productName) {
System.out.println("购买商品 -->> " + productName);
return "create order success";
}
}
import net.sf.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
/**
* cglib 代理接口
* @author: haibin.tang
* @date: 2021/2/5
*/
public class CgLibDynamicProxy implements InvocationHandler {
private Object target;
public CgLibDynamicProxy(Object target) {
this.target = target;
}
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
System.out.println("调用开始" + target.getClass().getName() + "#" + method.getName());
return method.invoke(target, args);
}
}
代理类示例
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public class StockService {
public int getStock() {
System.out.println("获取库存调用");
return 157;
}
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* cglib代理class
*
* @author: haibin.tang
* @date: 2021/2/5
*/
public class CglibMethodInterceptor implements MethodInterceptor {
public Object getProxy(Class superClass) {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);
enhancer.setSuperclass(superClass);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("调用开始" + obj.getClass().getName() + "#" + method.getName());
return proxy.invokeSuper(obj, args);
}
}
测试
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Proxy;
/**
* @author: haibin.tang
* @date: 2021/2/5
*/
public class Main {
public static void main(String[] args) {
//将cglib生成的代理类输出到指定的目录
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "e://cglib_class");
OrderService orderService = (OrderService) Proxy.newProxyInstance(CgLibDynamicProxy.class.getClassLoader(), new Class[]{OrderService.class}, new CgLibDynamicProxy(new OrderServiceImpl()));
System.out.println(orderService.create("HUAWEI P20 旗舰版"));
System.out.println("-------------------------------------------------------------------");
CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor();
StockService stockProxy = (StockService) cglibMethodInterceptor.getProxy(StockService.class);
System.out.println(stockProxy.getStock());
}
}
CGLIB动态代理原理
核心API
public interface MethodInterceptor extends Callback {
/**
* obj: Enhancer生成的动态代理类实例对象
* method: 真实调用方法
* args: 调用方法所需的参数
* proxy:
*/
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
}
/**
* 用于生成class
*/
net.sf.cglib.proxy.Enhancer#create()
public class MethodProxy {
/**
* 调用obj对象指定的方法
* obj: 被调用对象
* args: 调用方法所需参数
* 注意:当obj为MethodInterceptor#intercept 方法的第一个参数值的时候,这里会导致栈溢出,因为内部会出现死循环调用,具体为什么 往下面看
*/
public Object invoke(Object obj, Object[] args) throws Throwable;
/**
* 调用obj对象指定的super方法
* obj:被调用的对象
* args: 调用方法所需参数
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable;
}
生成的代理class
StockServiceb62322fb46217eb2.class
package com.nanxhs.proxy.cglib;
import com.nanxhs.proxy.cglib.StockService..EnhancerByCGLIB..b62322fb;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;
public class StockService$$EnhancerByCGLIB$$b62322fb$$FastClassByCGLIB$$46217eb2 extends FastClass {
.......省略
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
b62322fb var10000 = (b62322fb)var2;
int var10001 = var1;
try {
switch(var10001) {
case 7:
return new Integer(var10000.getStock());
case 8:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
.....
case 20:
return new Integer(var10000.CGLIB$getStock$0());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
.....省略
}
StockService558e11c5.class
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.nanxhs.proxy.cglib;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
public class StockService$$FastClassByCGLIB$$558e11c5 extends FastClass {
......
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
StockService var10000 = (StockService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Integer(var10000.getStock());
case 1:
return new Boolean(var10000.equals(var3[0]));
case 2:
return var10000.toString();
case 3:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
........
}
StockServiceb62322fb.class
package com.nanxhs.proxy.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class StockService$$EnhancerByCGLIB$$b62322fb extends StockService implements Factory {
....省略
//调用父级的业务代码方法---MethodProxy#invokeSuper 方法最终调用
final int CGLIB$getStock$0() {
return super.getStock();
}
//调用本对象实现的业务代码方法----MethodProxy#invoke方法最终调用,所以这里会导致栈溢出
public final int getStock() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//导致栈溢出的根源,var10000的实际类型是MethodInterceptor, 调用他自己的intercept方法,intercept方法内部又调用MethodProxy#invoke方法,最终造成了死循环
Object var1 = var10000.intercept(this, CGLIB$getStock$0$Method, CGLIB$emptyArgs, CGLIB$getStock$0$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.getStock();
}
}
.....省略
}
debug代码调用过程
MethodProxy#invokeSuper 流程
MethodProxy#invoke 流程
正确使用MethodProxy#invoke方法
解决invoke导致的栈溢出
为什么这样就不会栈溢出?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话