Java代理模式如何实现
- 后端开发
- 2025-06-13
- 4065
在Java中设置代理模式可通过系统属性或Proxy类实现,系统属性方式设置全局代理,如
System.setProperty("http.proxyHost", "proxy.example.com")
;Proxy类则为单个连接指定代理,通过
ProxySelector
动态管理,两种方法均支持HTTP/HTTPS/SOCKS协议,需注意代理验证和异常处理。
在Java中设置代理模式主要涉及两种实现方式:静态代理和动态代理(包括JDK动态代理和CGLIB动态代理),以下是详细实现指南:
静态代理(手动编写代理类)
原理:通过手动创建代理类,直接调用目标对象的方法,并在前后添加扩展逻辑。
// 1. 定义接口 interface UserService { void save(); } // 2. 实现目标类 class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存用户数据"); } } // 3. 创建代理类(关键) class UserServiceProxy implements UserService { private UserService target; // 目标对象 public UserServiceProxy(UserService target) { this.target = target; } @Override public void save() { System.out.println("【代理】操作前日志记录"); target.save(); // 调用目标方法 System.out.println("【代理】操作后资源清理"); } } // 4. 使用代理 public class StaticProxyDemo { public static void main(String[] args) { UserService target = new UserServiceImpl(); UserService proxy = new UserServiceProxy(target); proxy.save(); // 通过代理对象调用 } }
JDK动态代理(基于接口)
原理:利用java.lang.reflect.Proxy
在运行时生成代理类,要求目标对象必须实现接口。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 1. 实现InvocationHandler class LogHandler implements InvocationHandler { private Object target; // 目标对象 public LogHandler(Object target) { this.target = target; } @Override 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; } } // 2. 生成代理对象 public class JdkProxyDemo { public static void main(String[] args) { UserService target = new UserServiceImpl(); // 创建代理实例 UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), // 获取接口数组 new LogHandler(target) ); proxy.save(); // 调用代理方法 } }
CGLIB动态代理(基于类继承)
原理:通过字节码技术生成目标类的子类作为代理,无需实现接口(需添加依赖)。
-
添加Maven依赖:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
-
代码实现:
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
class UserServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(“【CGLIB代理】方法前增强”);
Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)方法
System.out.println(“【CGLIB代理】方法后增强”);
return result;
}
}
public class CglibProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class); // 设置目标类为父类
enhancer.setCallback(new UserServiceInterceptor());
UserService proxy = (UserService) enhancer.create(); // 创建代理对象
proxy.save();
}
---
### **关键对比与选型建议**
| 代理类型 | 优点 | 缺点 | 适用场景 |
|----------------|-------------------------------|-------------------------------|------------------------------|
| **静态代理** | 简单直观,无额外依赖 | 需手动编写代理类,维护成本高 | 简单方法增强或少量目标对象 |
| **JDK动态代理**| 自动生成代理类,减少重复代码 | 目标类必须实现接口 | 基于接口的代理(如Spring AOP)|
| **CGLIB代理** | 可代理无接口的类 | 无法代理final类/方法 | 代理普通类或第三方库 |
---
### **常见问题解决**
1. **JDK代理报`java.lang.ClassCastException`**
**原因**:目标类未实现接口。
**方案**:改用CGLIB代理或为目标类添加接口。
2. **CGLIB代理final方法无效**
**原因**:final方法无法被子类覆盖。
**方案**:避免代理final方法,或改用其他增强方式(如AspectJ)。
3. **性能优化**
- JDK 8+ 对动态代理进行了性能优化,多数场景无需担心。
- 高并发场景优先使用JDK代理(CGLIB生成类耗时较长)。
---
### **最佳实践**
1. **Spring框架中的选择**
- 若目标类实现接口 → 默认用JDK代理
- 若目标类无接口 → 自动切换CGLIB
- 强制使用CGLIB:在Spring Boot中配置`spring.aop.proxy-target-class=true`
2. **代理模式应用场景**
- 权限控制(如拦截未登录请求)
- 日志记录/性能监控
- 事务管理(如Spring声明式事务)
- 远程方法调用(RPC)
---
### **引用说明**
1. JDK动态代理官方文档:[`java.lang.reflect.Proxy`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html)
2. CGLIB开源项目地址:[GitHub - cglib/cglib](https://github.com/cglib/cglib)
3. 设计模式参考:《Head First Design Patterns》(O'Reilly)
4. Spring AOP原理:[Spring Framework Documentation](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop)
> 本文代码示例基于Java 11编写,依赖管理工具为Maven,实际使用时请确保环境兼容性,生产环境建议结合Spring AOP等成熟框架实现代理。