当前位置: 首页 > news >正文

深入解析:java设计模式七、代理模式

什么是代理模式

代理模式是一种常见的设计模式,它通过创建一个代理对象来控制对原始对象的访问。这种模式在现实生活中有很多类比,比如房产中介、律师代理等,他们都代表另一个人或组织执行某些功能。

在软件开发中,代理模式主要用于:

  • 控制对原始对象的访问
  • 添加额外的功能(如日志、权限检查)
  • 延迟创建开销大的对象
  • 提供远程访问的本地代表

静态代理

静态代理的基本概念

静态代理是通过显式创建一个代理类来实现的,这个代理类和原始类实现相同的接口。代理对象在调用原始对象方法的前后,可以添加额外的处理逻辑。

静态代理的实现示例

假设我们有一个用户数据库操作的场景,首先定义接口:

java

// 用户DAO接口
public interface UserDao {void save(User user);User findById(int id);void delete(int id);
}
// 用户实体类
public class User {private int id;private String name;private String email;// 构造方法、getter和setterpublic User(int id, String name, String email) {this.id = id;this.name = name;this.email = email;}// getter和setter方法省略...
}

接下来是实现类:

java

// 具体的用户DAO实现
public class UserDaoImpl implements UserDao {@Overridepublic void save(User user) {System.out.println("YA33: 保存用户信息到数据库 - " + user.getName());// 实际的数据库保存逻辑}@Overridepublic User findById(int id) {System.out.println("YA33: 从数据库查询用户ID - " + id);// 实际的数据库查询逻辑return new User(id, "用户" + id, "user" + id + "@example.com");}@Overridepublic void delete(int id) {System.out.println("YA33: 从数据库删除用户ID - " + id);// 实际的数据库删除逻辑}
}

然后是静态代理类:

java

// 静态代理类
public class UserDaoStaticProxy implements UserDao {private UserDao target;public UserDaoStaticProxy(UserDao target) {this.target = target;}@Overridepublic void save(User user) {System.out.println("YA33: [代理] 开始事务");try {target.save(user);System.out.println("YA33: [代理] 提交事务");} catch (Exception e) {System.out.println("YA33: [代理] 回滚事务");throw e;}}@Overridepublic User findById(int id) {System.out.println("YA33: [代理] 记录查询日志 - 查询用户ID: " + id);long startTime = System.currentTimeMillis();User user = target.findById(id);long endTime = System.currentTimeMillis();System.out.println("YA33: [代理] 查询耗时: " + (endTime - startTime) + "ms");return user;}@Overridepublic void delete(int id) {System.out.println("YA33: [代理] 权限检查");// 模拟权限检查if (checkPermission()) {target.delete(id);System.out.println("YA33: [代理] 删除操作完成");} else {System.out.println("YA33: [代理] 权限不足,删除操作被拒绝");}}private boolean checkPermission() {// 模拟权限检查逻辑return true;}
}

静态代理的使用

java

// 测试静态代理
public class StaticProxyTest {public static void main(String[] args) {// 创建目标对象UserDao target = new UserDaoImpl();// 创建代理对象UserDao proxy = new UserDaoStaticProxy(target);// 使用代理对象User user = new User(1, "YA33", "ya33@example.com");proxy.save(user);User foundUser = proxy.findById(1);System.out.println("找到用户: " + foundUser.getName());}
}

静态代理的优缺点

优点:

  • 结构简单,易于理解和实现
  • 可以在不修改目标对象的情况下添加功能
  • 符合开闭原则

缺点:

  • 如果接口增加方法,代理类和目标类都需要修改
  • 每个需要代理的类都需要创建一个对应的代理类,导致类数量增加
  • 代码重复,如果多个类需要相同的增强功能,需要在每个代理类中重复编写

动态代理

动态代理的基本概念

动态代理在运行时动态生成代理对象,不需要像静态代理那样为每个类显式编写代理类。Java提供了两种主要的动态代理方式:JDK动态代理和CGLIB动态代理。

JDK动态代理

JDK动态代理原理

JDK动态代理基于接口实现,使用Java反射机制在运行时创建代理对象。核心类是java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

JDK动态代理实现

java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 创建动态代理对象
public class JdkProxyFactory {// 维护一个目标对象private Object target;public JdkProxyFactory(Object target) {this.target = target;}// 给目标对象生成代理对象public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("YA33: [JDK代理] 开始执行方法: " + method.getName());// 方法执行前增强preProcess(method, args);long startTime = System.currentTimeMillis();// 执行目标对象方法Object returnValue = method.invoke(target, args);long endTime = System.currentTimeMillis();// 方法执行后增强postProcess(method, args, returnValue, endTime - startTime);System.out.println("YA33: [JDK代理] 方法执行完成: " + method.getName());return returnValue;}private void preProcess(Method method, Object[] args) {System.out.println("YA33: [JDK代理] 前置处理 - 方法: " + method.getName());if (args != null) {for (int i = 0; i < args.length; i++) {System.out.println("YA33: [JDK代理] 参数" + i + ": " + args[i]);}}}private void postProcess(Method method, Object[] args, Object returnValue, long duration) {System.out.println("YA33: [JDK代理] 后置处理 - 方法: " + method.getName());System.out.println("YA33: [JDK代理] 执行耗时: " + duration + "ms");if (returnValue != null) {System.out.println("YA33: [JDK代理] 返回值: " + returnValue);}}});}
}
JDK动态代理使用示例

java

// 测试JDK动态代理
public class JdkProxyTest {public static void main(String[] args) {// 创建目标对象UserDao target = new UserDaoImpl();// 创建代理工厂JdkProxyFactory factory = new JdkProxyFactory(target);// 获取代理对象UserDao proxy = (UserDao) factory.getProxyInstance();// 使用代理对象User user = new User(1, "YA33", "ya33@example.com");proxy.save(user);User foundUser = proxy.findById(1);System.out.println("找到用户: " + foundUser.getName());proxy.delete(1);}
}

CGLIB动态代理

CGLIB动态代理原理

CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它通过继承目标类并重写方法来实现代理,因此不需要目标类实现接口。

CGLIB动态代理实现

首先需要添加CGLIB依赖:

xml


cglibcglib3.3.0

然后实现CGLIB代理:

java

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// CGLIB代理工厂
public class CglibProxyFactory implements MethodInterceptor {// 维护目标对象private Object target;public CglibProxyFactory(Object target) {this.target = target;}// 给目标对象创建代理对象public Object getProxyInstance() {// 1. 工具类Enhancer en = new Enhancer();// 2. 设置父类en.setSuperclass(target.getClass());// 3. 设置回调函数en.setCallback(this);// 4. 创建子类(代理对象)return en.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("YA33: [CGLIB代理] 开始执行方法: " + method.getName());// 方法执行前增强preProcess(method, args);long startTime = System.currentTimeMillis();// 执行目标对象的方法Object returnValue = method.invoke(target, args);long endTime = System.currentTimeMillis();// 方法执行后增强postProcess(method, args, returnValue, endTime - startTime);System.out.println("YA33: [CGLIB代理] 方法执行完成: " + method.getName());return returnValue;}private void preProcess(Method method, Object[] args) {System.out.println("YA33: [CGLIB代理] 前置处理 - 方法: " + method.getName());if ("save".equals(method.getName())) {System.out.println("YA33: [CGLIB代理] 数据验证...");}if ("delete".equals(method.getName())) {System.out.println("YA33: [CGLIB代理] 权限验证...");}}private void postProcess(Method method, Object[] args, Object returnValue, long duration) {System.out.println("YA33: [CGLIB代理] 后置处理 - 方法: " + method.getName());System.out.println("YA33: [CGLIB代理] 执行耗时: " + duration + "ms");if ("findById".equals(method.getName()) && returnValue != null) {User user = (User) returnValue;System.out.println("YA33: [CGLIB代理] 查询结果: " + user.getName() + " (" + user.getEmail() + ")");}}
}
CGLIB动态代理使用示例

java

// 测试CGLIB动态代理
public class CglibProxyTest {public static void main(String[] args) {// 创建目标对象 - 注意这里不需要接口UserDaoImpl target = new UserDaoImpl();// 创建代理工厂CglibProxyFactory factory = new CglibProxyFactory(target);// 获取代理对象UserDaoImpl proxy = (UserDaoImpl) factory.getProxyInstance();// 使用代理对象User user = new User(1, "YA33", "ya33@example.com");proxy.save(user);User foundUser = proxy.findById(1);System.out.println("找到用户: " + foundUser.getName());}
}

静态代理与动态代理对比

实现方式对比

特性静态代理JDK动态代理CGLIB动态代理
实现方式手动编写代理类基于接口,使用Proxy类基于继承,使用Enhancer类
是否需要接口
性能较高中等(反射调用)较高(方法调用优化)
灵活性
依赖JDK自带需要CGLIB库

应用场景

静态代理适用场景:

  • 代理类较少,功能简单
  • 需要明确控制代理逻辑
  • 性能要求极高的场景

JDK动态代理适用场景:

  • 目标对象实现了接口
  • 需要代理多个类,且有相同接口
  • AOP编程

CGLIB动态代理适用场景:

  • 目标对象没有实现接口
  • 需要高性能的代理
  • Spring AOP默认使用方式

在MyBatis-Spring中的应用

在MyBatis-Spring框架中,动态代理被广泛应用于Mapper接口的实现。框架在启动时会为每个Mapper接口创建动态代理对象,当调用接口方法时,代理对象会将方法调用转换为SQL执行。

MyBatis Mapper代理示例

java

// Mapper接口
public interface UserMapper {User selectUserById(int id);void insertUser(User user);void updateUser(User user);void deleteUser(int id);
}
// 使用示例
@Autowired
private UserMapper userMapper; // 实际上是一个动态代理对象
public void testMapper() {User user = userMapper.selectUserById(1);System.out.println("YA33: 查询到用户: " + user.getName());
}

总结

代理模式是软件开发中非常重要的设计模式,它通过引入代理对象来控制对原始对象的访问。静态代理简单直观但灵活性差,动态代理则提供了更大的灵活性。

  • 静态代理:适用于代理类较少、功能明确的场景
  • JDK动态代理:基于接口,适用于目标类已实现接口的场景
  • CGLIB动态代理:基于继承,适用于目标类没有接口的场景,性能较高

在实际开发中,Spring框架、MyBatis等众多优秀框架都大量使用了动态代理技术,理解代理模式对于掌握这些框架的原理至关重要。

http://www.jsqmd.com/news/49724/

相关文章:

  • 《程序员修炼之道:从小工到专家》阅读笔记4
  • 单智能体系统
  • mysql真好用
  • 招聘广告:人形机器人领域,强化学习方向需要的技能
  • 黑马程序员SpringCloud微服务开发与实战-微服务04
  • CF1870G MEXanization - Link
  • 软件工程学习日志2025.11.24
  • 黄仁勋GTC华盛顿主题演讲:加速计算与AI的下一个“阿波罗时刻” - 实践
  • 2025-11-23~24 hetao1733837的刷题记录
  • 人工智能 —— 教培 —— 技校 —— 授课内容
  • 深入解析:数独解题算法lua脚本
  • 老鼠和奶酪 关于修改地图我找到了不可行之处
  • Hanoi和全排列
  • Trae搭建Android 开发中 MVVM 架构,使用指南
  • 2025/11/24~2025/11/28 做题笔记 - sb
  • IPD流程用什么项目管理工具?飞书项目、Primavera P6、Jira、Windchill 功能对比与选型
  • CF2061H2 Kevin and Stones (Hard Version) 题解
  • 详细介绍:Java外功基础1Spring Web MVC构建现代Web应用的基石
  • 大盘风险控制策略分析报告 - 2025年11月24日 - 20:52:39
  • 解码服务器IO模型
  • winfrom 操作列 动态按钮
  • 蓝桥杯-Python-基础语法
  • 电脑重启后WiFi服务没有启动导致WiFi无法开启
  • 大盘风险控制策略分析报告 - 2025年11月24日 - 20:51:47
  • Oracle 数据库体系结构详解
  • LRU缓存-leetcode
  • 总结-esp-idf 接口与抽象层设计
  • 洛谷-训练题-算法1-2
  • 高性能AI股票预测分析报告 - 2025年11月24日 - 20:46:52
  • 兄弟们我是好