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的内部逻辑。这种设计提高了代码的可复用性和扩展性,同时遵循了设计模式中的开闭原则------对扩展开放,对修改关闭。

相关推荐
刷帅耍帅3 小时前
设计模式-享元模式
设计模式·享元模式
刷帅耍帅3 小时前
设计模式-模版方法模式
设计模式
刷帅耍帅4 小时前
设计模式-桥接模式
设计模式·桥接模式
MinBadGuy5 小时前
【GeekBand】C++设计模式笔记5_Observer_观察者模式
c++·设计模式
刷帅耍帅6 小时前
设计模式-生成器模式/建造者模式Builder
设计模式·建造者模式
杨半仙儿还未成仙儿14 小时前
Spring框架:Spring Core、Spring AOP、Spring MVC、Spring Boot、Spring Cloud等组件的基本原理及使用
spring boot·spring·mvc
无理 Java1 天前
【技术详解】SpringMVC框架全面解析:从入门到精通(SpringMVC)
java·后端·spring·面试·mvc·框架·springmvc
椰椰椰耶1 天前
【Spring】@RequestMapping、@RestController和Postman
java·后端·spring·mvc
蜡笔小新..1 天前
【设计模式】软件设计原则——开闭原则&里氏替换&单一职责
java·设计模式·开闭原则·单一职责原则
性感博主在线瞎搞1 天前
【面向对象】设计模式概念和分类
设计模式·面向对象·中级软件设计师·设计方法