动态代理主要是解耦与增强,将抽象与实现进行解耦,对已有的实现进行增强。
有目标类,对目标类进行额外的业务增强,没有目标类,就抽象与实现解耦。
java动态代理可以对接口实现的非final方法进行AOP切面增强。
// 接口
public interface UserService {
void saveUser(String name);
}
// 目标类【不是必须的,可以只要代理实现】
public class UserServiceImpl implements UserService {
public void saveUser(String name) {
System.out.println("保存用户: " + name);
}
}
// InvocationHandler实现
public class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前: " + method.getName());
Object result = method.invoke(target, args); // 调用目标方法【不是必须的,可以只要代理实现】
System.out.println("方法调用后");
return result;
}
}
// 使用动态代理
public class Main {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();//【不是必须的,可以只要代理实现】
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LogHandler(realService)
);
proxy.saveUser("Alice"); // 输出增强后的逻辑
}
}
Java动态代理通过运行时生成字节码实现接口代理,将方法调用转发至InvocationHandler,从而解耦业务逻辑(接口与目标类是早期业务模块代码)与横切关注点(InvocationHandler实现类切点业务关注点)。其核心在于Proxy类的字节码生成与类加载机制,结合反射实现灵活的方法增强。尽管存在性能开销和仅支持接口的局限,但在多数场景下仍为AOP和动态扩展的首选方案。
public final class $Proxy0 extends Proxy implements Subject {
// 静态方法表:缓存接口方法对应的Method对象
private static Method m1; // hashCode()
private static Method m2; // equals()
private static Method m3; // toString()
private static Method m4; // 接口方法doSomething()
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("hashCode");
m2 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("Subject").getMethod("doSomething");
} catch (Exception e) { /* 异常处理 */ }
}
// 构造函数:传入InvocationHandler
public $Proxy0(InvocationHandler h) {
super(h); // Proxy的构造方法设置handler
}
// 接口方法实现
@Override
public final void doSomething() {
try {
super.h.invoke(this, m4, null); // 调用handler.invoke()
} catch (Throwable e) { /* 异常处理 */ }
}
// Object方法重写(如hashCode、equals、toString)
@Override
public final int hashCode() {
return (int) super.h.invoke(this, m1, null);
}
}
通过配置 -Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true 可以查看生成的代码
+-----------+ +----------+ +----------------+ +---------------+ +------------------+
| Client | | Proxy | | ProxyGenerator | | ClassLoader | | $Proxy0 |
+-----------+ +----------+ +----------------+ +---------------+ +------------------+
| | | | |
|--1: newProxyInstance()------------->| | |
| | | | |
| |--2: getProxyClass0()------------------->| |
| | | | |
| |<--3: 检查缓存是否存在-------------------| |
| | | | |
| |--4: 缓存未命中,生成新代理类------------>| |
| | | | |
| | |--5: generateProxyClass()----------------->|
| | | | |
| | |<--6: 生成字节码byte[]---------------------|
| | | | |
| |--7: defineClass()---------------------->| |
| | | | |
| |<--8: 加载$Proxy0类----------------------| |
| | | | |
| |--9: 缓存代理类------------------------->| |
| | | | |
| |--10: 实例化$Proxy0(newInstance())------>| |
| | | | |
|<--11: 返回$Proxy0实例-------------------------------------| |
| | | | |
```
```通过生成的代理对象调用方法
Client $Proxy0 InvocationHandler UserServiceImpl
| | | |
|--doSomething()->| | |
| |---invoke()---------->| |
| | |----target.doSomething()->|
| | |<-----------return--------|
| |<-------return--------| |
|<--return--------| | |
```