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中的处理方法。
java 复制代码
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类型的处理器。
java 复制代码
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使用。
java 复制代码
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()方法来确定。
java 复制代码
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的内部逻辑。这种设计提高了代码的可复用性和扩展性,同时遵循了设计模式中的开闭原则------对扩展开放,对修改关闭。

相关推荐
Damon_X3 小时前
桥接模式(Bridge Pattern)
设计模式·桥接模式
越甲八千8 小时前
重温设计模式--享元模式
设计模式·享元模式
码农爱java9 小时前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式
越甲八千10 小时前
重温设计模式--中介者模式
windows·设计模式·中介者模式
犬余10 小时前
设计模式之桥接模式:抽象与实现之间的分离艺术
笔记·学习·设计模式·桥接模式
Theodore_102211 小时前
1 软件工程——概述
java·开发语言·算法·设计模式·java-ee·软件工程·个人开发
越甲八千12 小时前
重拾设计模式--组合模式
设计模式·组合模式
思忖小下15 小时前
梳理你的思路(从OOP到架构设计)_设计模式Composite模式
设计模式·组合模式·eit
机器视觉知识推荐、就业指导15 小时前
C++设计模式:组合模式(公司架构案例)
c++·后端·设计模式·组合模式
越甲八千16 小时前
重拾设计模式--工厂模式(简单、工厂、抽象)
c++·设计模式