SpringMVC对异步请求的支持

工具类 WebAsyncUtils

public abstract class WebAsyncUtils {
   

	/**
	 * The name attribute containing the {@link WebAsyncManager}.
	 * 用于存放WebAsyncManager对象的属性
	 */
	public static final String WEB_ASYNC_MANAGER_ATTRIBUTE =
			WebAsyncManager.class.getName() + ".WEB_ASYNC_MANAGER";
			
	/**
	 * 针对当前的request获取一个WebAsyncManager
	 */
	public static WebAsyncManager getAsyncManager(ServletRequest servletRequest) {
   
		WebAsyncManager asyncManager = null;
		Object asyncManagerAttr = servletRequest.getAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE);
		if (asyncManagerAttr instanceof WebAsyncManager) {
   
			asyncManager = (WebAsyncManager) asyncManagerAttr;
		}
		if (asyncManager == null) {
   
			asyncManager = new WebAsyncManager();
			servletRequest.setAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE, asyncManager);
		}
		return asyncManager;
	}

	/**
	 * 重载方法
	 */
	public static WebAsyncManager getAsyncManager(WebRequest webRequest) {
   
		int scope = RequestAttributes.SCOPE_REQUEST;
		WebAsyncManager asyncManager = null;
		Object asyncManagerAttr = webRequest.getAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE, scope);
		if (asyncManagerAttr instanceof WebAsyncManager) {
   
			asyncManager = (WebAsyncManager) asyncManagerAttr;
		}
		if (asyncManager == null) {
   
			asyncManager = new WebAsyncManager();
			webRequest.setAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE, asyncManager, scope);
		}
		return asyncManager;
	}

	/**
	创建一个AsyncWebRequest对象,其实就是StandardServletAsyncWebRequest,
	该类继承至WebRequest,所以上面的重载方法是对此使用的。
	**/
	public static AsyncWebRequest createAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
   
		return new StandardServletAsyncWebRequest(request, response);
	}
}

这里我先重点看一下StandardServletAsyncWebRequest的结构,以便后续理解:

StandardServletAsyncWebRequest继承图
从以上我们了解到以下信息:
1.WebAsyncManager 对象会缓存在request的属性中。
2.StandardServletAsyncWebRequest 实现了AsyncListener,也就意味着异步请求会回调StandardServletAsyncWebRequest。
3.StandardServletAsyncWebRequest 继承至AbstractRequestAttributes

接下来我们咨询分析一下StandardServletAsyncWebRequest这个类。

StandardServletAsyncWebRequest

首先是RequestAttributes接口, 它提供了基于request的属性访问能力。并支持不同请求范围的属性访问(request/session), 这里重点说一个方法:

/**
   这个方法是注册一些当特定属性销毁的时候进行回调的回调方法,
   其实这个销毁通常指的是整个范围的销毁,例如request返回或者session范围,而不是一个单独的属性删除,
   例如removeAttribite(String key)。
***/
	void registerDestructionCallback(String name, Runnable callback, int scope);

接下来看下它的抽象实现类:AbstractRequestAttributes

//该类提供了一种请求完成机制,主要是针对特定请求销毁回调和session attributes更新。
public abstract class AbstractRequestAttributes implements RequestAttributes {
   

	/** Map from attribute name String to destruction callback Runnable. */
	//回调列表
	protected final Map<String, Runnable> requestDestructionCallbacks = new LinkedHashMap<>(8);

	private volatile boolean requestActive = true;


	/**
	 * Signal that the request has been completed.
	 * <p>Executes all request destruction callbacks and updates the
	 * session attributes that have been accessed during request processing.
	 * 请求完成,执行所有的request销毁回调,更新所有的request执行期间被访问过的session属性。
	 */
	public void requestCompleted() {
   
		executeRequestDestructionCallbacks();
		updateAccessedSessionAttributes();
		this.requestActive = false;
	}

   //………………省略一堆代码…………

	/**
	 * Execute all callbacks that have been registered for execution
	 * after request completion.
	 */
	private void executeRequestDestructionCallbacks() {
   
		synchronized (this.requestDestructionCallbacks) {
   
			for (Runnable runnable : this.requestDestructionCallbacks.values()) {
   
				runnable.run();
			}
			this.requestDestructionCallbacks.clear();
		}
	}

	protected abstract void updateAccessedSessionAttributes();
}

抽象类AbstractRequestAttributes保存了request请求完成的回调列表,并通过requestActive来标记request是否处于活动状态。 更新被访问的session属性由子类具体实现。

ServletRequestAttributes

该类是基于servlet的RequestAttributes实现,通过servlet request和http sesison来访属性, http session与 global session没有区别。

	private final HttpServletRequest request;

	@Nullable
	private HttpServletResponse response;

	@Nullable
	private volatile HttpSession session;

	private final Map<String, Object> sessionAttributesToUpdate = new ConcurrentHashMap<>(1);

该类是所有行为都是基于它持有的HttpServletRequest,HttpServletResponse 和 HttpSession 。

ServletWebRequest

该类扩展了WebRequest的一些能力,针对web,一般都会提供,getParameter,getLocale,getContextPath 等能力。

StandardServletAsyncWebRequest

该类在ServletWebRequest的能力之上增加了异步请求的能力,主要由AsyncWebRequest定义。主要的异步能力包括:setTimeout,addTimeoutHandler,startAsync,dispatch,isAsyncComplete等,看到这些方法是不是感觉和servlet异步请求规范中的AsyncContext很像 ? 是的,几乎就是一样。来看一下spring对这些接口的具体实现:

public class StandardServletAsyncWebRequest extends ServletWebRequest implements AsyncWebRequest, AsyncListener {
   

	private Long timeout;  //异步超时时间
    //依赖servlet的规范,看到这里我们基本上能想到刚才说的很相似的接口都是依赖它来实现的了。
	private AsyncContext asyncContext;  
    //是否异步请求完成(原子变量)
	private AtomicBoolean asyncCompleted = new AtomicBoolean(false);
    //异步超时后的回调处理器
	private final List<Runnable> timeoutHandlers = new ArrayList<>();
    //异常处理器
	private final List<Consumer<Throwable>> exceptionHandlers = new ArrayList<>();
    //异步完成后的回调
	private final List<Runnable> completionHandlers = new ArrayList<>();
	//………………省略一万行代码…………
}

该类的实例变量如上,总体来看就是依赖AsyncContext, 并且保存了一堆回调。 再来看下它的方法体,其中一些简单的set方法就不看了,这里只看稍微有一点逻辑的:

	@Override
	public boolean isAsyncStarted() {
   
		return (this.asyncContext != null && getRequest().isAsyncStarted());
	}
	@Override
	public boolean isAsyncComplete() {
   
		return this.asyncCompleted.get();
	}
	@Override
	public void startAsync() {
   
		Assert.state(getRequest().isAsyncSupported(),
				"Async support must be enabled on a servlet and for all filters involved " +
				"in async request processing. This is done in Java code using the Servlet API " +
				"or by adding \"<async-supported>true</async-supported>\" to servlet and " +
				"filter declarations in web.xml.");
		Assert.state(!isAsyncComplete(), "Async processing has already completed");

		if (isAsyncStarted()) {
   
			return
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值