静态代理
需要被代理的目标对象
//火车站买票
public class TrainStationTicket{
public void sell() {
System.out.println("卖票");
}
}
代理对象
public class ProxyPoint{
private TrainStationTicket trainStationTicket;
public ProxyPoint(TrainStationTicket trainStationTicket) {
this.trainStationTicket = trainStationTicket;
}
public void sell() {
System.out.println("卖票前宣传");
trainStationTicket.sell();
System.out.println("卖票后售后");
}
}
动态代理
1. JDK 动态代理(基于接口)
(1)实现原理
-
JDK 动态代理使用 反射 和 接口 来生成代理对象。
-
核心类:
java.lang.reflect.Proxy(生成代理类)java.lang.reflect.InvocationHandler(处理代理逻辑)
(2)为什么需要接口?
-
字节码生成限制:
- JDK 动态代理在运行时 动态生成一个类,该类继承
Proxy并 实现目标接口。 - 由于 Java 是单继承的,代理类已经继承了
Proxy,无法再继承其他类,因此只能通过 实现接口 的方式代理。
- JDK 动态代理在运行时 动态生成一个类,该类继承
-
方法调用机制:
- 代理对象的所有方法调用都会委托给
InvocationHandler.invoke()。 - 接口提供了明确的方法签名,确保代理类能正确拦截方法。 接口
- 代理对象的所有方法调用都会委托给
public interface Service {
boolean send(String msg);
}
需要被代理的类
public class ServiceImpl implements Service{
@Override
public boolean send(String msg) {
System.out.println("发送消息:"+msg);
return true;
}
}
实现InvocationHandler接口,通过invoke方法自定义增强逻辑
public class ProxyHandler implements InvocationHandler {
private final Object target;
public ProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理前增强操作");
Object res = method.invoke(target, args);
System.out.println("代理后增强操作");
return res;
}
}
代理类工厂,用于创建代理类
public class ProxyHandlerFactory {
public static Object getServiceProxy(Object Target){
return Proxy.newProxyInstance(Target.getClass().getClassLoader(),Target.getClass().getInterfaces(),new ProxyHandler(Target));
}
}
Proxy.newProxyInstance(Target.getClass().getClassLoader(),Target.getClass().getInterfaces(),new ProxyHandler(Target));的底层实现原理
Java 动态代理通过 Proxy.newProxyInstance 创建代理对象,其底层原理如下:
- 生成代理类字节码: 根据传入的接口列表,在内存中动态生成一个实现这些接口的代理类 $Proxy0(继承 Proxy 类并实现目标接口)。
- 加载代理类: 使用指定的类加载器(通常是目标对象的类加载器)将生成的字节码加载为 Class 对象。
- 创建代理实例: 通过反射调用代理类的构造函数,传入 InvocationHandler 实现类(如 ProxyHandler),创建代理对象。
- 方法调用转发: 当调用代理对象的方法时,会转交给 InvocationHandler 的 invoke 方法处理,实现如增强逻辑、转发调用等。
简而言之:动态生成实现接口的代理类 → 加载该类 → 创建其实例 → 所有方法调用被转发到 InvocationHandler。
2. CGLIB 动态代理(基于继承)
(1)实现原理
-
CGLIB(Code Generation Library)通过 字节码增强 动态生成目标类的 子类,并重写方法。
-
核心类:
net.sf.cglib.proxy.Enhancer(生成代理类)net.sf.cglib.proxy.MethodInterceptor(方法拦截逻辑)
(2)为什么不需要接口?
-
继承机制:
- CGLIB 生成的代理类 直接继承目标类,因此不依赖接口。
- 它通过 方法拦截(MethodInterceptor) 实现增强。
-
覆盖非 final 方法:
- CGLIB 会重写目标类的非
final方法(final方法无法代理)。
- CGLIB 会重写目标类的非
注意: JDK 9+ 的模块系统(JPMS)限制了对某些类的反射访问,特别是 java.lang.ClassLoader.defineClass 方法。CGLIB 在生成代理类时尝试通过反射调用该方法,但被 JVM 拒绝,导致 InaccessibleObjectException。所以需要添加动态参数--add-opens java.base/java.lang=ALL-UNNAMED
public class ClibProxy {
static class Target {
public void foo() {
System.out.println("target foo");
}
@Override
public String toString() {
return super.toString();
}
}
public static void main(String[] param) {
// 目标对象
Target target = new Target();
// 代理对象
Target proxy = (Target) Enhancer.create(Target.class,
(MethodInterceptor) (p, method, args, methodProxy) -> {
System.out.println("proxy before...");
// Object result = method.invoke(target, args);
// 另一种调用方法,不需要目标对象实例
Object result = methodProxy.invokeSuper(p, args);
System.out.println("proxy after...");
return result;
});
// 调用代理
proxy.foo();
}
@Override
public String toString() {
return super.toString();
}
}
总结
| 代理方式 | 实现机制 | 是否需要接口 | 性能 | 适用场景 |
|---|---|---|---|---|
| JDK 动态代理 | 接口 + 反射 | ✅ 必须 | 较低 | 目标类已实现接口 |
| CGLIB | 继承 + 字节码增强 | ❌ 不需要 | 较高 | 目标类无接口或需更高性能 |
- JDK 代理 是 Java 标准库的一部分,但受限于接口。
- CGLIB 更灵活,但需注意
final方法的限制。 - Spring AOP 根据目标类自动选择,也可手动配置。