Spring MVC源码中设计模式——适配器模式

适配器模式介绍

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

应用场景:

  • 1、系统需要使用现有的类,而此类的接口不符合系统的需要。

  • 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。

  • 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

优点:

  • 促进代码重用:通过适配器,原本不兼容的接口可以协同工作,提高了现有代码的重用性。
    提高透明性:客户端代码通过适配器与目标接口交互,而不需要直接依赖原有接口,这样即便接口发生变化,客户端代码也无需改动。

  • 灵活性:在系统引入新技术或者第三方库时,可以通过适配器模式将其融入现有系统中,而不影响其他部分的代码。
    缺点:

  • 系统复杂性增加:引入适配器模式会增加系统中的类的数量,有时候可能会使得系统结构变得复杂。

  • 过多使用可能导致混乱:如果在一个系统中大量使用适配器模式,可能会引起接口和实现的混乱,从而降低代码的可读性和可维护性。

  • 性能开销:每次调用都需要通过适配器进行转换,这可能会带来一定的性能开销,尤其是在高性能要求的系统中需要特别注意。

源码中应用

Spring MVC中广泛使用了适配器模式,它用于将不同类型的Controller适配到统一的请求处理流程中。

在Spring MVC框架中,DispatcherServlet作为中心调度器负责处理所有的HTTP请求,但它并不直接执行请求处理方法,这项工作由HandlerAdapter来完成。HandlerAdapter在这里起到了适配器的作用,它将Controller(需要适配的类)适配到统一的接口上,以便DispatcherServlet可以透明地调用任何类型的Controller处理方法。

以下是适配器模式在Spring MVC中的应用细节:

  • 定义适配器接口:定义一个HandlerAdapter接口,包含两个主要方法——supports()用来判断适配器是否支持对应的Controller,handle()用来执行Controller中的处理方法。
public interface HandlerAdapter {

	/**
	*给定一个处理程序实例,返回此{@code HandlerAdapter}
	*可以支持它。典型的HandlerAdapters将根据处理程序做出决定
	类型HandlerAdapters通常每个只支持一种处理程序类型。
	*/
	boolean supports(Object handler);

	/**
		*使用给定的处理程序来处理此请求。
		*/
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	/**
		*与HttpServlet的{@code getLastModified}方法的合约相同。
		*/
	@Deprecated
	long getLastModified(HttpServletRequest request, Object handler);

}
  • 实现适配器:对于每种类型的Controller,提供相应的HandlerAdapter实现类。例如,HttpRequestHandlerAdapter用于适配HttpRequestHandler类型的处理器。
    在这里插入图片描述
public class HttpRequestHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		((HttpRequestHandler) handler).handleRequest(request, response);
		return null;
	}

	@Override
	@SuppressWarnings("deprecation")
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}
  • 存放适配器实例:Spring容器启动时,会将所有定义好的HandlerAdapter实现类实例存放在一个List集合中供DispatcherServlet使用。
private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// 在ApplicationContext中查找所有HandlerAdapter
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// 排序HandlerAdapters 
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// 不处理,并添加默认的HandlerAdapters 
			}
		}

		// 通过注册,确保至少有一个HandlerAdapter
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}
  • 选择适配器:当请求到达时,DispatcherServlet会根据Handler的类型找到对应的HandlerAdapter。这个过程通常通过遍历HandlerAdapter列表并使用supports()方法来确定。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}
  • 处理请求:一旦找到了合适的HandlerAdapter,就会调用其handle()方法来执行Controller中的请求处理方法,并返回ModelAndView对象。

总的来说,适配器模式在Spring MVC中起到了至关重要的作用,它使得框架能够灵活地处理各种类型的Controller而无需修改DispatcherServlet的内部逻辑。这种设计提高了代码的可复用性和扩展性,同时遵循了设计模式中的开闭原则——对扩展开放,对修改关闭。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/421391.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt Creator配置MSVC编译环境、调试环境

在windows上开发&#xff0c;一般使用Qt Creator自带mingw编译器&#xff0c;编译和调试都很方便&#xff0c;安装Qt时勾选后&#xff0c;自动配置完毕。 但是有时候我们需要使用MSVC的编译器&#xff0c;这个时候我们没法直接使用&#xff0c;需要配置环境才能使用&#xff0…

Vue中<style scoped lang=“scss“>的含义

这段代码中的<style scoped lang"scss">是HTML和Vue框架结合使用时常见的一个模式&#xff0c;具体含义如下&#xff1a; scoped&#xff1a;这是一个Vue.js特有的属性&#xff0c;用来指定样式只应用于当前组件的元素。没有这个属性时&#xff0c;样式会全局应…

网络卡顿是怎么回事?

网络卡顿是指在网络通信过程中&#xff0c;数据传输出现延迟或中断&#xff0c;导致用户在使用网络时出现卡顿、延迟或不流畅的情况。例如&#xff1a;系统响应时间长&#xff0c;网页加载速度慢&#xff1b;视频或游戏掉帧&#xff0c;导致画面卡顿或不流畅&#xff1b;音视频…

qsort函数 结构体比较(strcmp函数(比较字符串的大小))

strcmp函数应用于qsort函数&#xff0c;排序创建函数指针时比较字符串大小。 这里我创建了一个简单的学生结构体&#xff0c;这个结构体只包含名字跟年龄两个信息。 在创建函数指针cmp_stu_age后&#xff0c;进行年龄大小比较&#xff0c;强制类型转换成stu*。 int cmp_stu_ag…

Springboot 项目读取yaml的配置文件信息给静态方法使用,以及通过配置 ResourceBundle 类读取config.properties

读取yaml 的配置文件 配置文件信息 iot_saas_tenement:user_id: 7........8d9bprivate_key: MII.......qQbj_url: http://4.....5:8088project_name: iot_s.......rojectdevice_name: te.....ice 创建一个类 ProxyProperties 读取配置文件信息&#xff0c;并对外提供get方法 …

Python爬虫——Urllib库-2

编解码 问题引入 例如&#xff1a; https://www.baidu.com/s?wd章若楠 https://www.baidu.com/s?wd%E7%AB%A0%E8%8B%A5%E6%A5%A0 第二部分的一串乱码就是章若楠 如果这里是写的章若楠就会 产生这样的错误 所以我们就可以使用get请求方式的quote方法了 get请求方式的q…

EasyRecovery2024国产免费的手机数据恢复软件

一、功能介绍 EasyRecovery手机数据恢复软件是一款功能全面的数据恢复工具&#xff0c;专为移动设备设计。其主要功能包括&#xff1a; 文件恢复&#xff1a;能够恢复手机中因各种原因丢失的文件&#xff0c;如照片、视频、音频、文档等。深度扫描&#xff1a;通过深度扫描手…

CSS 盒子模型(box model)

概念 所有HTML元素可以看作盒子&#xff0c;在CSS中&#xff0c;"box model"这一术语是用来设计和布局时使用CSS盒模型本质上是一个盒子&#xff0c;封装周围的HTML元素&#xff0c;它包括&#xff1a;外边距(margin)&#xff0c;边框(border)&#xff0c;内边距(pad…

Linux/Centos 部署静态IP,解决无法访问目标主机、Destination Host Unreachable、无法ping通互联网的问题

Linux/Centos 部署IP&#xff0c;解决无法访问目标主机、Destination Host Unreachable、无法ping通互联网的问题 Linux/Centos 部署静态IP查物理机/自身电脑的IP设置VMware上的虚拟网络编辑器设置网卡IP&#xff0c;激活至此就可访问百度了 Linux/Centos 部署静态IP 需要注意…

Zookeeper学习1:概述、安装、应用场景、集群配置

文章目录 概述安装LinuxWindows 配置参数集群参考配置文件配置步骤流程启动 概述 Zookeeper&#xff1a; 为分布式框架组件提供协调服务的中间件 【类似&#xff1a;文件系统通知机制】 负责存储上下层应用关系的数据以及接收观察者注册监听&#xff0c;一旦观察查关心的数据发…

力扣SQL50 无效的推文 查询

Problem: 1683. 无效的推文 思路 &#x1f468;‍&#x1f3eb; 参考 char_length(str)&#xff1a;计算 str 的字符长度length(str)&#xff1a;计算 str 的字节长度 Code select tweet_id from Tweets where char_length(content) > 15;

Docker中使用Tomcat并部署war工程

系列文章目录 文章目录 系列文章目录前言一、构建镜像二、运行镜像三、列出正在运行的容器四、停止正在运行的容器 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文…

java 基础上(1)(核心知识搭配代码)

前言 java的学习分为了上部分以及下部分进行学习&#xff0c;上部分就是对于java的基础知识&#xff0c;面向对象上&#xff0c;面向对象下&#xff0c;异常操作&#xff0c;javaApi&#xff1b;下部主要是集合&#xff0c;泛型&#xff0c;反射&#xff0c;IO流&#xff0c;J…

AcWing 466. 回文日期

先贴个题目&#xff1a; 以及原题链接&#xff1a;466. 回文日期 - AcWing题库https://www.acwing.com/problem/content/468/ 这题乍一看有点恶心&#xff0c;如果枚举日期还要判断合法性&#xff0c;然后每个日期再判断是不是回文&#xff0c;即麻烦&#xff0c;时间复杂度又高…

CSS 自测题 -- 用 flex 布局绘制骰子(一、二、三【含斜三点】、四、五、六点)

一点 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>css flex布局-画骰子</title><sty…

APP自动化测试-入门示例

入门示例 通过上一篇博客APP自动化测试介绍-CSDN博客的学习&#xff0c;相信大家对APP自动化测试已经有了一定的了解&#xff0c;下面演示一下入门示例 1. 配置Appium 1.1. 点击Appium图标&#xff0c;打开服务器&#xff1a; 1.2. 点击Edit Configurations,进入配置页面&am…

vue3项目中如何一个vue组件中的一个div里面的图片铺满整个屏幕样式如何设置

在Vue 3项目中&#xff0c;要使一个div内的图片铺满整个屏幕&#xff0c;你需要确保几个关键点&#xff1a;div元素和图片元素的样式设置正确&#xff0c;以及确保它们能够覆盖整个视口&#xff08;viewport&#xff09;。以下是一个简单的步骤和代码示例&#xff0c;帮助你实现…

帝国cms7.5仿非小号区块链门户资讯网站源码 带手机版

帝国cms7.5仿非小号区块链门户资讯网站源码 带手机版 带自动采集 开发环境&#xff1a;帝国cms 7.5 安装环境&#xff1a;phpmysql 包含火车头采集规则和模块&#xff0c;采集目标站非小号官网。 专业的数字货币大数据平台模板&#xff0c;采用帝国cms7.5内核仿制&#xff0…

Android挖取原图手指触点区域RectF(并框线标记)放大到ImageView宽高与矩阵mapRadius,Kotlin

Android挖取原图手指触点区域RectF(并框线标记)放大到ImageView宽高与矩阵mapRadius&#xff0c;Kotlin 这里 Android挖取原图中心区域RectF(并框线标记)放大到ImageView宽高&#xff0c;Kotlin-CSDN博客 实现的是把原图中心区域的一片小图挖取出来放大放到下面的ImageView里面…

STM32------分析GPIO寄存器

一、初始LED原理图 共阴极led LED发光二极管&#xff0c;需要有电流通过才能点亮&#xff0c;当有电压差就会产生电流 二极管两端的电压差超过2.7v就会有电流通过 电阻的作用 由于公式IV/R 不加电阻容易造成瞬间电流无穷大 发光二极管工作电流为10-20MA 3.3v / 1kΩ 3.…
最新文章