当前位置:首页 > 后端开发 > 正文

Java代理模式如何实现

在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在运行时生成代理类,要求目标对象必须实现接口。

Java代理模式如何实现  第1张

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动态代理(基于类继承)

原理:通过字节码技术生成目标类的子类作为代理,无需实现接口(需添加依赖)。

  1. 添加Maven依赖

    <dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>3.3.0</version>
    </dependency>
  2. 代码实现

    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等成熟框架实现代理。
0