代理模式

代理模式

代理模式的核心就是在不修改原代码的前提下,增强方法行为

静态代理

手写一个代理类,实现目标类相同的接口,内层包着其真实对象。

接口

1
2
3
public interface UserService {
void save();
}

目标类

1
2
3
4
5
6
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户");
}
}

静态代理类(手写)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UserServiceProxy implements UserService {

private final UserService target;

public UserServiceProxy(UserService target) {
this.target = target;
}

@Override
public void save() {
System.out.println("开启事务");
target.save();
System.out.println("提交事务");
}
}

使用

1
2
3
4
UserService service =
new UserServiceProxy(new UserServiceImpl());

service.save();

优缺点:

  • 直观
  • 无反射,性能好
  • 类爆炸(一个接口一个代理)
  • 复用性差

动态代理

代理类是运行时生成的,
方法调用统一拦截,
可复用一套增强逻辑。

JDK动态代理

  • 位于java.lang.reflect.Proxy
  • 只能代理接口
  • 编写 InvocationHandler 实现类
  • 通过 Proxy.newProxyInstance() 创建代理对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 1. 定义接口
public interface UserService {
void save(String name);
}

// 2. 目标实现类
public class UserServiceImpl implements UserService {
public void save(String name) {
System.out.println("保存用户: " + name);
}
}

// 3. 手写 InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
private final Object target; // 被代理的对象

public MyInvocationHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【前置增强】方法调用前");
Object result = method.invoke(target, args); // 调用真实对象的方法
System.out.println("【后置增强】方法调用后");
return result;
}
}

// 4. 创建代理工厂类
import java.lang.reflect.Proxy;

public class ProxyFactory {
public static <T> T getProxy(T target) {
InvocationHandler handler = new MyInvocationHandler(target);

@SuppressWarnings("unchecked")
T proxy = (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);

return proxy;
}
}

// 5. 使用工厂类创建代理并调用
public class Main {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = ProxyFactory.getProxy(realService);

proxy.save("张三");
}
}

使用匿名函数类

1
2
3
4
5
6
7
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增强逻辑
return method.invoke(target, args);
}
};

使用Lambda表达式

1
2
3
4
5
6
7
8
UserService proxy = (UserService) Proxy.newProxyInstance(
loader,
interfaces,
(proxyObj, method, methodArgs) -> {
System.out.println("拦截方法: " + method.getName());
return method.invoke(realService, methodArgs);
}
);

CGLIB动态代理

CGLIB动态代理解决了JDK动态代理只能代理接口的问题,CGLIB使用了ASM技术,能够在运行时修改字节码。CGLIB通过继承的方法实现代理。Spring的AOP中,如果目标对象实现了接口那么使用JDK动态代理,如果没有则使用CGLIB进行代理。

  • CGLIB在运行时生成一个目标类的子类
  • 重写父类中所有非final,非static,非private的方法
  • 在重写方法中插入拦截代码
  • 调用原方法使用super.method()委托给父类
  1. 目标类
1
2
3
4
5
6
7
8
9
10
public class UserService {
public void save(String name) {
System.out.println("保存用户: " + name);
}

// final 方法无法被代理
public final void finalizeSave() {
System.out.println("最终保存");
}
}
  1. 实现MethodInterceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("【前置增强】调用方法: " + method.getName());
Object result = proxy.invokeSuper(obj, args); // 调用父类(原始)方法
System.out.println("【后置增强】方法结束");
return result;
}
}
  1. 创建被代理对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import net.sf.cglib.proxy.Enhancer;

public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class); // 设置父类
enhancer.setCallback(new MyMethodInterceptor()); // 设置拦截器

UserService proxy = (UserService) enhancer.create(); // 创建代理实例

proxy.save("张三"); // 会被拦截
proxy.finalizeSave(); // 不会被拦截(final 方法)
}
}

代理模式
https://yicizhang00.github.io/posts/编程语言/Java/Java基础/代理模式/
作者
Yici Zhang
发布于
2025年12月31日
许可协议