Spring的处理器映射器与适配器的架构设计

目录

一、前言

二、Spring的处理器适配器的架构设计

1、Spring的适配器架构图

2、HandlerAdapter接口层

3、HttpRequestHandlerAdapter实现类

4、SimpleControllerHandlerAdapter实现类

5、SimpleServletHandlerAdapter实现类

6、AbstractHandlerMethodAdapter抽象子类

三、Spring的处理器映射器的架构设计

1、HttpRequestHandler及其子类

2、HttpRequestHandler

3、DefaultServletHttpRequestHandler 实现类


一、前言

    学框架源码,不必把源码的每一句都读懂,我们更需要了解的是一些架构设计、设计思想、灵活运用了哪些知识点、良好的编码风格等,以便应用到我们的实际开发工作中,学以致用。

二、Spring的处理器适配器的架构设计

1、Spring的适配器架构图

Spring的处理器映射器与适配器的架构设计_第1张图片

                                                             适配器架构图 

2、HandlerAdapter接口层

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.lang.Nullable;


public interface HandlerAdapter {

	/**
	 * 给定一个处理程序实例,返回此 HandlerAdapter 是否支持它。典型的 HandlerAdapter 将根据处理程序类型作出决策。
	 * HandlerAdapter 通常每个只支持一种处理程序类型。
	 *
	 * 

A typical implementation: *

{@code * return (handler instanceof MyHandler); * } * @param handler the handler object to check * @return whether or not this object can use the given handler */ boolean supports(Object handler); /** * 使用给定的处理程序来处理此请求。所需的工作流可能有很大的不同。 * * @param request current HTTP request * @param response current HTTP response * @param handler the handler to use. This object must have previously been passed * to the {@code supports} method of this interface, which must have * returned {@code true}. * @throws Exception in case of errors * @return 一个带有视图名称和所需模型数据的 ModelAndView 对象,如果请求已经被直接处理,则为 null */ @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** * 与 HttpServlet 的 getLastAmendment 方法相同的契约。如果处理程序类中没有支持,可以简单地返回 -1。 */ long getLastModified(HttpServletRequest request, Object handler); }

核心重点方法就是supports()和handle()方法。该接口作用及注意事项:

  • MVC 框架 SPI,支持核心 MVC 工作流的参量化。
  • 接口,必须为每个处理程序类型实现该接口才能处理请求。此接口用于允许 DispatcherServlet 无限扩展。 DispatcherServlet 通过此接口访问所有已安装的处理程序,这意味着它不包含特定于任何处理程序类型的代码。
  • 注意,处理程序可以是 Object 类型的。这是为了使来自其他框架的处理程序能够在没有自定义编码的情况下与这个框架集成,并且允许不服从任何特定 Java 接口的注释驱动的处理程序对象。
  • 此接口不适用于应用程序开发人员。对于那些希望开发自己的 Web 工作流的处理程序来说,它是可用的。
  • 注意: HandlerAdapter 实现可以实现 Orded 接口,以便能够指定 DispatcherServlet 应用的排序顺序(因此是优先级)。无序实例被视为最低优先级。

这里说的扩展就是根据新的需求添加HandlerAdapter的子类实现类/抽象类。

3、HttpRequestHandlerAdapter实现类

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
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

可见根据处理器映射器获取适配器,如果supports()方法中命中为HttpRequestHandler类型,那么在获取适配器后调用handle()方法,就会调用子类的逻辑。HttpRequestHandlerAdapter会委派给HttpRequestHandler处理,但是返回null。

4、SimpleControllerHandlerAdapter实现类

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

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

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

		return ((Controller) handler).handleRequest(request, response);
	}

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

}

可见根据处理器映射器获取适配器,如果supports()方法中命中为Controller类型,那么在获取适配器后调用handle()方法,就会调用子类的逻辑。SimpleControllerHandlerAdapter会委派给Controller处理,返回ModelAndView。

注意:这是一个 SPI 类,应用程序代码不直接使用它。

5、SimpleServletHandlerAdapter实现类

public class SimpleServletHandlerAdapter implements HandlerAdapter {

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

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

		((Servlet) handler).service(request, response);
		return null;
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		return -1;
	}

}

可见根据处理器映射器获取适配器,如果supports()方法中命中为Servlet类型,那么在获取适配器后调用handle()方法,就会调用子类的逻辑。SimpleServletHandlerAdapter会委派给Servlet处理,但是返回null。

注意:

1、适配器与通用 DispatcherServlet 一起使用 Servlet 接口。调用 Servlet 的服务方法来处理请求。

2、默认情况下不会激活此适配器; 它需要在 DispatcherServlet 上下文中定义为 bean。然后,它将自动应用于实现 Servlet 接口的映射处理程序 bean。

3、请注意,定义为 bean 的 Servlet 实例将不会接收初始化和销毁回调,除非在DispatcherServlet 上下文中定义了特殊的后处理器(如 SimpleServletPostProcessor)。

4、或者,考虑用 Spring 的 ServletWrappingController 包装 Servlet。这是特别合适的现有 Servlet 类,允许指定 Servlet 初始化参数等。

6、AbstractHandlerMethodAdapter抽象子类

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {

	private int order = Ordered.LOWEST_PRECEDENCE;


	public AbstractHandlerMethodAdapter() {
		// no restriction of HTTP methods by default
		super(false);
	}


	/**
	 * Specify the order value for this HandlerAdapter bean.
	 * 

The default value is {@code Ordered.LOWEST_PRECEDENCE}, meaning non-ordered. * @see org.springframework.core.Ordered#getOrder() */ public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; } /** * This implementation expects the handler to be an {@link HandlerMethod}. * 此实现期望处理程序是 HandlerMethod * @param handler the handler instance to check * @return whether or not this adapter can adapt the given handler */ @Override public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); } /** * Given a handler method, return whether or not this adapter can support it. * @param handlerMethod the handler method to check * @return whether or not this adapter can adapt the given method */ protected abstract boolean supportsInternal(HandlerMethod handlerMethod); /** * This implementation expects the handler to be an {@link HandlerMethod}.此实现期望处理程序是 HandlerMethod */ @Override @Nullable public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } /** * Use the given handler method to handle the request. * @param request current HTTP request * @param response current HTTP response * @param handlerMethod handler method to use. This object must have previously been passed to the * {@link #supportsInternal(HandlerMethod)} this interface, which must have returned {@code true}. * @return a ModelAndView object with the name of the view and the required model data, * or {@code null} if the request has been handled directly * @throws Exception in case of errors */ @Nullable protected abstract ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception; /** * This implementation expects the handler to be an {@link HandlerMethod}. */ @Override public final long getLastModified(HttpServletRequest request, Object handler) { return getLastModifiedInternal(request, (HandlerMethod) handler); } /** * Same contract as for {@link javax.servlet.http.HttpServlet#getLastModified(HttpServletRequest)}. * @param request current HTTP request * @param handlerMethod handler method to use * @return the lastModified value for the given handler */ protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod); }

可见根据处理器映射器获取适配器,如果supports()方法中命中为HandlerMethod类型,那么在获取适配器后调用handle()方法,就会调用子类的逻辑。AbstractHandlerMethodAdapter会委派给其子类RequestMappingHandlerAdapter 处理,返回ModelAndView。

三、Spring的处理器映射器的架构设计

之所以先讲适配器的设计,是因为其中涉及了映射器的高层,映射器的高层有多种接口或者类。其中有的类的结构图,有的没,这里仅以部分为例

1、HttpRequestHandler及其子类

Spring的处理器映射器与适配器的架构设计_第2张图片

2、HttpRequestHandler


@FunctionalInterface
public interface HttpRequestHandler {

	/**
	 * Process the given request, generating a response.处理请求,并响应
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws ServletException in case of general errors
	 * @throws IOException in case of I/O errors
	 */
	void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException;

}

注意:

1、处理 HTTP 请求的组件的普通处理程序接口,类似于 Servlet。只声明 ServletException 和 IOException,以便在任何HttpServlet 中使用。这个接口实际上是 HttpServlet 的直接等价物,简化为一个中心句柄方法。

2、在 Spring 样式中公开 HttpRequestHandler bean 的最简单方法是在 Spring 的根 web 应用上下文中定义它,并在 web.xml 中定义 HttpRequestHandlerServlet,通过它的 servlet-name 指向目标 HttpRequestHandler bean,这需要匹配目标 bean 的名称。

3、在 Spring 的 DispatcherServlet 中支持作为处理程序类型,能够与调度程序的高级映射和拦截设施进行交互。 这是公开 HttpRequestHandler 的推荐方法,同时保持处理程序实现不受 DispatcherServlet 环境的直接依赖。

4、通常实现为直接生成二进制响应,不涉及单独的视图资源。这使它与 Spring 的 Web MVC 框架中的 Controller 有所不同。没有 ModelAndViewreturn 值为 DispatcherServlet 以外的调用方提供了更清晰的签名,表明永远不会有要呈现的视图。

5、从 Spring 2.0开始,Spring 的基于 HTTP 的远程导出程序,比如 HttpInvokerServiceExporter 和HessianServiceExporter,实现了这个接口,而不是更广泛的 Controller 接口,以尽可能减少对 Spring 特定 Web 基础设施的依赖。

6、注意,HttpRequestHandlers 可以选择性地实现 LastAmendment 接口,就像 Controllers 可以一样,只要它们在 Spring 的 DispatcherServlet中运行。但是,这通常是不必要的,因为 HttpRequestHandlers通常只支持 POST 请求。或者,处理程序可以在其处理方法中手动实现“ If-Amendment-since”HTTP 头处理。

3、DefaultServletHttpRequestHandler 实现类


public class DefaultServletHttpRequestHandler implements HttpRequestHandler, ServletContextAware {

	/** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish. */
	private static final String COMMON_DEFAULT_SERVLET_NAME = "default";

	/** Default Servlet name used by Google App Engine. */
	private static final String GAE_DEFAULT_SERVLET_NAME = "_ah_default";

	/** Default Servlet name used by Resin. */
	private static final String RESIN_DEFAULT_SERVLET_NAME = "resin-file";

	/** Default Servlet name used by WebLogic. */
	private static final String WEBLOGIC_DEFAULT_SERVLET_NAME = "FileServlet";

	/** Default Servlet name used by WebSphere. */
	private static final String WEBSPHERE_DEFAULT_SERVLET_NAME = "SimpleFileServlet";


	@Nullable
	private String defaultServletName;

	@Nullable
	private ServletContext servletContext;


	/**
	 * Set the name of the default Servlet to be forwarded to for static resource requests.
	 */
	public void setDefaultServletName(String defaultServletName) {
		this.defaultServletName = defaultServletName;
	}

	/**
	 * If the {@code defaultServletName} property has not been explicitly set,
	 * attempts to locate the default Servlet using the known common
	 * container-specific names.
	 */
	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
		if (!StringUtils.hasText(this.defaultServletName)) {
			if (this.servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {
				this.defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
			}
			else if (this.servletContext.getNamedDispatcher(GAE_DEFAULT_SERVLET_NAME) != null) {
				this.defaultServletName = GAE_DEFAULT_SERVLET_NAME;
			}
			else if (this.servletContext.getNamedDispatcher(RESIN_DEFAULT_SERVLET_NAME) != null) {
				this.defaultServletName = RESIN_DEFAULT_SERVLET_NAME;
			}
			else if (this.servletContext.getNamedDispatcher(WEBLOGIC_DEFAULT_SERVLET_NAME) != null) {
				this.defaultServletName = WEBLOGIC_DEFAULT_SERVLET_NAME;
			}
			else if (this.servletContext.getNamedDispatcher(WEBSPHERE_DEFAULT_SERVLET_NAME) != null) {
				this.defaultServletName = WEBSPHERE_DEFAULT_SERVLET_NAME;
			}
			else {
				throw new IllegalStateException("Unable to locate the default servlet for serving static content. " +
						"Please set the 'defaultServletName' property explicitly.");
			}
		}
	}


	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		Assert.state(this.servletContext != null, "No ServletContext set");
		RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
		if (rd == null) {
			throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
					this.defaultServletName + "'");
		}
		rd.forward(request, response);
	}

}

注意:

由于没有返回ModelAndView,所以直接调用了servlet包下的forward()方法转发处理。

1、 用于使用 Servlet 容器的“默认”Servlet 提供静态文件

2、当 DispatcherServlet 映射到“/”时,此处理程序将与“/*”映射一起使用,从而覆盖 Servlet 容器对静态资源的默认处理。到此处理程序的映射通常应该排序为链中的最后一个,以便只有在无法匹配其他更具体的映射(即到控制器的映射)时才执行。

3、通过转发通过defaultServletName属性指定的名称获得的RequestDispatcher来处理请求。在大多数情况下,defaultServletName 不需要显式设置,因为处理程序会在初始化时检查是否存在已知容器的默认 Servlet,如 Tomcat、 Jetty、 RESH、 WebLogic 和WebSphere。但是,当运行在默认 Servlet 名称不为人所知的容器中,或者在通过服务器配置定制了 Servlet 名称的容器中时,需要显式地设置defaultServletName。
 

到这里粗略的讲解了SpringMVC中映射器与适配器的架构设计,关于适配器的话讲解得比较到位了,映射器的话会比较粗略,后面看看还有什么再补充上去。

你可能感兴趣的:(Spring家族,spring,java)