当前位置: 首页 > 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

<!-- Maven依赖 -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

然后实现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.dtcms.com/a/519836.html

相关文章:

  • 【底层机制】【Android】AIDL原理与实现机制详解
  • 网站提交链接入口网站 seo优化
  • idea建有servlet类的web项目
  • Redis相关八股
  • zookeeper数据迁移
  • Java 大视界 -- Java 大数据机器学习模型在智能客服多轮对话系统中的优化策略
  • 怎么上网做网站dede网站模板怎么改
  • 网站关键词查询怎么用腾讯云主机建设网站
  • WGJ技术解析与应用:构建下一代智能数据处理引擎
  • js基础:05、对象(创建对象、属性名及属性值、基本数据及引用数据类型、对象字面量)
  • 苍穹外卖是如何从0搭建一个标准的 Maven 多模块项目​​的?
  • 网站建设竞品调研上海注册公司免费地址
  • 宣传网站制作方案网站架构演变过程
  • K8S 二进制集群搭建(一主两从)
  • 每日一个C语言知识:C typedef
  • 交叉编译FFmpeg:从x264到RK3588部署实战
  • LeetCode算法日记 - Day 82: 环形子数组的最大和
  • Leetcode 36
  • 深入理解epoll:为什么推荐使用epoll_create1而不是epoll_create?
  • 公司被其它人拿来做网站营销渠道的概念
  • 在 Linux 下使用 I2C(Inter-Integrated Circuit)进行用户态编程 — 教程与实战
  • 替代HT1621B液晶驱动显示模块芯片程序演示
  • C++和OpenGL实现3D游戏编程【连载26】——添加TransformComponent组件(设置子物体的位移、旋转、缩放)
  • 常规条形光源在工业视觉检测上的应用
  • Zotero插件安装
  • Llama Factory、Unsloth与Hugging Face三大微调平台深度对比分析
  • 电脑卡在 “正在准备 Windows”?5 步解决:从等待到重装
  • 优惠券网站要怎么做的佛山禅城网站建设
  • 基于深度学习计算s21参数,在射频中的应用
  • 微服务day01——拆分作业参考