Java代理模式
Java代理模式[编辑 | 编辑源代码]
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过一个代理对象控制对另一个对象的访问。代理模式常用于延迟初始化、访问控制、日志记录等场景,是Java中常见的设计模式之一。
简介[编辑 | 编辑源代码]
代理模式的核心思想是为某个对象提供一个代理,以控制对该对象的访问。代理对象可以在客户端和目标对象之间起到中介的作用,从而在不修改目标对象代码的情况下增强其功能。
代理模式通常分为以下三种类型:
- 静态代理:在编译时确定代理关系。
- 动态代理:在运行时动态生成代理类。
- 虚拟代理:延迟加载目标对象,直到真正需要时才创建。
静态代理[编辑 | 编辑源代码]
静态代理是最简单的代理实现方式,代理类和目标类实现相同的接口,并在代理类中调用目标类的方法。
示例代码[编辑 | 编辑源代码]
// 1. 定义接口
interface Image {
void display();
}
// 2. 实现目标类
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading image: " + filename);
}
@Override
public void display() {
System.out.println("Displaying image: " + filename);
}
}
// 3. 实现代理类
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename); // 延迟加载
}
realImage.display();
}
}
// 4. 客户端代码
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
// 第一次调用会加载图片
image.display();
// 第二次调用直接显示,无需重新加载
image.display();
}
}
输出结果[编辑 | 编辑源代码]
Loading image: test.jpg Displaying image: test.jpg Displaying image: test.jpg
解释[编辑 | 编辑源代码]
1. 定义`Image`接口,包含`display()`方法。 2. `RealImage`是实际加载和显示图片的类。 3. `ProxyImage`控制对`RealImage`的访问,实现了延迟加载功能。 4. 客户端通过代理访问图片,第一次调用时才会真正加载图片。
动态代理[编辑 | 编辑源代码]
Java动态代理利用反射机制在运行时动态创建代理类,比静态代理更灵活。主要通过`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`实现。
示例代码[编辑 | 编辑源代码]
import java.lang.reflect.*;
// 1. 定义接口
interface Calculator {
int add(int a, int b);
int subtract(int a, int b);
}
// 2. 实现目标类
class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int subtract(int a, int b) {
return a - b;
}
}
// 3. 实现InvocationHandler
class LoggingHandler implements InvocationHandler {
private Object target;
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
}
}
// 4. 客户端代码
public class DynamicProxyDemo {
public static void main(String[] args) {
Calculator realCalculator = new CalculatorImpl();
Calculator proxy = (Calculator) Proxy.newProxyInstance(
Calculator.class.getClassLoader(),
new Class[]{Calculator.class},
new LoggingHandler(realCalculator)
);
System.out.println("Result: " + proxy.add(5, 3));
System.out.println("Result: " + proxy.subtract(5, 3));
}
}
输出结果[编辑 | 编辑源代码]
Before method: add After method: add Result: 8 Before method: subtract After method: subtract Result: 2
解释[编辑 | 编辑源代码]
1. 定义`Calculator`接口和实现类`CalculatorImpl`。 2. `LoggingHandler`实现`InvocationHandler`,在方法调用前后添加日志。 3. 通过`Proxy.newProxyInstance()`动态创建代理对象。 4. 客户端调用代理对象的方法时,会自动调用`invoke()`方法。
代理模式类图[编辑 | 编辑源代码]
应用场景[编辑 | 编辑源代码]
代理模式在以下场景中特别有用:
- 远程代理:为远程对象提供本地代表(如RMI)。
- 虚拟代理:延迟加载大资源对象(如图片、文件)。
- 保护代理:控制对敏感对象的访问权限。
- 智能引用:在访问对象时执行额外操作(如引用计数、线程安全检查)。
优缺点[编辑 | 编辑源代码]
优点[编辑 | 编辑源代码]
- 职责清晰,符合单一职责原则。
- 扩展性强,可以在不修改目标对象的情况下增强功能。
- 客户端可以透明地使用代理对象。
缺点[编辑 | 编辑源代码]
- 静态代理需要为每个服务创建代理类,工作量大。
- 动态代理使用反射,性能略低于直接调用。
- 增加了系统的复杂度。
进阶应用[编辑 | 编辑源代码]
Spring AOP中的代理[编辑 | 编辑源代码]
Spring框架广泛使用代理模式实现AOP(面向切面编程)。Spring AOP默认使用JDK动态代理(针对接口)或CGLIB(针对类)来创建代理对象。
示例:Spring AOP代理[编辑 | 编辑源代码]
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature().getName());
}
}
性能考虑[编辑 | 编辑源代码]
对于性能敏感的场景,可以考虑:
- 缓存代理对象,避免重复创建。
- 使用字节码生成工具(如Byte Buddy)替代反射。
- 在编译时生成代理(如Annotation Processing Tool)。
总结[编辑 | 编辑源代码]
代理模式是Java中强大的设计模式,它通过引入代理对象来控制对目标对象的访问。无论是简单的静态代理还是灵活的动态代理,都能有效地解耦客户端和目标对象,增强系统功能。理解代理模式对于掌握Java高级特性(如Spring AOP)至关重要。