一次调试dispatcherServlet

7 篇文章 0 订阅

init()方法

这个是servlet的init()方法

	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// Set bean properties from init parameters.
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		// Let subclasses do whatever initialization they like.
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

主要是doDispatch

/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

/**
*
Determine handler for the current request.
getHandler返回执行链(handler(一个方法)+ 拦截器集合)

*/

				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.




				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				

// 应用默认视图名

				applyDefaultViewName(processedRequest, mv);
//后置的拦截器方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			//视图解析
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

getHandler返回执行链(handler(一个方法)+ 拦截器集合)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				if (logger.isTraceEnabled()) {
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

这个getHandler对象是一个通过handerMapping返回的执行对象。如果这个handlerMapping不为空,其实这里的handlerMapping就是我们配置的requestHandlerMapping,然后handlerMapping对象通过gethandler方法获得执行链,

HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		ModelAndView mv = null;

在这里请求的mappedHandler是一个执行链的对象,包含拦截器和handler对象,

HandlerExecutionChain 的对象mappedHandler

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
这个调用实现类的方法是如下:
拦截器的成员
handler
拦截器链表


package org.springframework.web.servlet;

/**
 * Handler execution chain, consisting of handler object and any handler interceptors.
 * Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
 * @see HandlerInterceptor
 */
public class HandlerExecutionChain {

	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

	private final Object handler;

	@Nullable
	private HandlerInterceptor[] interceptors; //拦截器数组

	@Nullable
	private List<HandlerInterceptor> interceptorList;//拦截器链表

	private int interceptorIndex = -1;

	/**
	 * 通过handler创建一个新的处理器执行链对象
	 * @参数 handler 用来执行的handlker对象
	 */
	public HandlerExecutionChain(Object handler) {
		this(handler, (HandlerInterceptor[]) null);
	}

	/**
	 * 通过handler和拦截器创建一个新的处理器执行链对象
	 * @param handler 用来执行的handlker对象
	 * @param interceptors 要应用的拦截器可变长数组
	 * (in the given order) before the handler itself executes
	 */
	public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
		if (handler instanceof HandlerExecutionChain) {
			HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
			this.handler = originalChain.getHandler();
			this.interceptorList = new ArrayList<>();   //是一个arrayList的对象
			CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
			CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
		}
		else {
			this.handler = handler;
			this.interceptors = interceptors;
		}
	}

	/**
	 * 返回handler
	 */
	public Object getHandler() {
		return this.handler;
	}
/**
*添加拦截器对象
*/
	public void addInterceptor(HandlerInterceptor interceptor) {
		initInterceptorList().add(interceptor);
	}

	public void addInterceptors(HandlerInterceptor... interceptors) {
		if (!ObjectUtils.isEmpty(interceptors)) {
			CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList());
		}
	}
//初始化拦截器链表,数组一律转为链表并返回
	private List<HandlerInterceptor> initInterceptorList() {
		if (this.interceptorList == null) {
			this.interceptorList = new ArrayList<>();
			if (this.interceptors != null) {
				// An interceptor array specified through the constructor
				CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
			}
		}
		this.interceptors = null;
		return this.interceptorList;
	}

	/**
	 * Return the array of interceptors to apply (in the given order).
	 * @return the array of HandlerInterceptors instances (may be {@code null})
	 */
	@Nullable
	public HandlerInterceptor[] getInterceptors() {
		if (this.interceptors == null && this.interceptorList != null) {
			this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
		}
		return this.interceptors;
	}


	/**
	 * Apply preHandle methods of registered interceptors.
	 * 应用注册拦截器的预处理方法。
	 * @return {@code true} if the execution chain should proceed with the
	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
	 * that this interceptor has already dealt with the response itself.
如果执行链应该继续下一个拦截器或处理程序本身。否则,DispatcherServlet假设这个拦截器已经处理了响应本身。
	 */
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

	/**
	 * Apply postHandle methods of registered interceptors.
	 */
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}

	/**
	 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
	 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
	 * has successfully completed and returned true.
	 */
	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

	/**
	 * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
	 */
	void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				if (interceptors[i] instanceof AsyncHandlerInterceptor) {
					try {
						AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
						asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
					}
					catch (Throwable ex) {
						logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
					}
				}
			}
		}
	}


	/**
	 * Delegates to the handler's {@code toString()}.
	 */
	@Override
	public String toString() {
		Object handler = getHandler();
		StringBuilder sb = new StringBuilder();
		sb.append("HandlerExecutionChain with handler [").append(handler).append("]");
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			sb.append(" and ").append(interceptors.length).append(" interceptor");
			if (interceptors.length > 1) {
				sb.append("s");
			}
		}
		return sb.toString();
	}

}

HandlerAdapter的对象ha

HandlerAdapter的接口中定义了三个方法:

(1)boolean supports(Object handler); 判断是否支持传入的Handler

(2)ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 用来使用Handler处理请求

(3)long getLastModified(HttpServletRequest request, Object handler); 用来获取资料的Last-Modified值。
这里我们可以看一下这个doDisptch方法

doDispathch()这个方法通过调用getHandlerAdapter来获取适当的handlerAdapter

/**
	 * Return the HandlerAdapter for this handler object.
	 * 为这个handler对象返回合适的HandlerAdapter
	 * @param handler the handler object to find an adapter for
	 * 参数handler 为这个handler对象寻找合适adapter
	 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
	 */
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
	<!--	如果当前DispatchServlet对象的handlerAdapter对象数组不为空,遍历这个数组并且寻找handler的合适adapter通过supports方法实现-->
			for (HandlerAdapter ha : this.handlerAdapters) {
			//这个handleradapter是通过配置然后通过上下文环境getbean获取的然后添加到
				if (logger.isTraceEnabled()) {
					logger.trace("Testing handler adapter [" + ha + "]");
				}
				if (ha.supports(handler)) {
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

ModelAndViewContainer

在这里插入图片描述

public class ModelAndViewContainer {
	private boolean ignoreDefaultModelOnRedirect = false;
	@Nullable
	private Object view;
	private final ModelMap defaultModel = new BindingAwareModelMap();
	@Nullable
	private ModelMap redirectModel;
	private boolean redirectModelScenario = false;
	@Nullable
	private HttpStatus status;
	private final Set<String> noBinding = new HashSet<>(4);
	private final Set<String> bindingDisabled = new HashSet<>(4);
	private final SessionStatus sessionStatus = new SimpleSessionStatus();
	private boolean requestHandled = false;

关于返回String的视图处理

/**
视图是否是通过Dispatcherservlet通过视图解析器解析的名称指定的视图引用。 
	 */
	public boolean isViewReference() {
		return (this.view instanceof String);
	}
if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}

整个getModelAndView的方法。
在这里插入图片描述

执行完mv = ha.handle(processedRequest, response, mappedHandler.getHandler());,执行applyDefaultViewName

applyDefaultViewName

/**
 * 我们需要视图名称转换吗? 
 */
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
	if (mv != null && !mv.hasView()) {
		String defaultViewName = getDefaultViewName(request);
		if (defaultViewName != null) {
			mv.setViewName(defaultViewName);
		}
	}
}

/**
如果没有视图名,
*/
	protected String getDefaultViewName(HttpServletRequest request) throws Exception {
		return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
	}


public String getViewName(HttpServletRequest request) {
	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
	return (this.prefix + transformPath(lookupPath) + this.suffix);
}

解析:
在这里插入图片描述
在运行完applyDefaultViewName后
mv的view就变成了请求的requestmapping字符串,这里会变成index
这里完了之后就到后置拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
完了之后是异常拦截器

完了之后执行processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);方法。

渲染视图的方法

在这里插入图片描述

DispatherServlet类的render()方法
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);

		View view;
		String viewName = mv.getViewName();
		if (viewName != null) {
			// 如果视图名不为空,需要解析视图名
			//解析视图的调用栈如下图所示
			//传入的是视图名字,Model,locale和request
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
			if (mv.getStatus() != null) {
				response.setStatus(mv.getStatus().value());
			}
			view.render(mv.getModelInternal(), request, response);
			//mv.getModelInternal() 就是model
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

将视图名,模型解析为View对象的方法

@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
		Locale locale, HttpServletRequest request) throws Exception {

	if (this.viewResolvers != null) {
		for (ViewResolver viewResolver : this.viewResolvers) {
			View view = viewResolver.resolveViewName(viewName, locale);
			if (view != null) {
				return view;
			}
		}
	}
	return null;
}

传入的参数debug情况如下
在这里插入图片描述
在这里插入图片描述

ViewResolver类

package org.springframework.web.servlet;
/**
 * Interface to be implemented by objects that can resolve views by name.
通过视图名字解析视图
 * @see org.springframework.web.servlet.view.InternalResourceViewResolver
 * @see org.springframework.web.servlet.view.ResourceBundleViewResolver
 * @see org.springframework.web.servlet.view.XmlViewResolver
 */
public interface ViewResolver {

	/**
	 * 通过名字解析给定视图
	 * <p>Note: To allow for ViewResolver chaining, a ViewResolver should
	 * return {@code null} if a view with the given name is not defined in it.
	 * However, this is not required: Some ViewResolvers will always attempt
	 * to build View objects with the given name, unable to return {@code null}
	 * (rather throwing an exception when View creation failed).
	 * @param viewName name of the view to resolve
	 * @param locale Locale in which to resolve the view.
	 * ViewResolvers that support internationalization should respect this.
	 * @return the View object, or {@code null} if not found
	 * (optional, to allow for ViewResolver chaining)
	 * @throws Exception if the view cannot be resolved
	 * (typically in case of problems creating an actual View object)
	 */
	@Nullable
	View resolveViewName(String viewName, Locale locale) throws Exception;
}

我们

配置的解析器的父类

public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver 

AbstractCachingViewResolver的resolveViewName

public View resolveViewName(String viewName, Locale locale) throws Exception {
		if (!isCache()) {
			return createView(viewName, locale);
		}
		else {
		//通过视图名和locale信息构造缓存key
	
			Object cacheKey = getCacheKey(viewName, locale);
	//通过 ConcurrentHashMap中key找View
			View view = this.viewAccessCache.get(cacheKey);
					//判断View访问缓存中是否有该缓存key
			if (view == null) {
			
				synchronized (this.viewCreationCache) {
					view = this.viewCreationCache.get(cacheKey);
					if (view == null) {
						// 让子类创建View对象。子类判断是否可以处理,是否重定向,或者转发,否则调用父类的createView()方法
						 
						view = createView(viewName, locale);
						if (view == null && this.cacheUnresolved) {
							view = UNRESOLVED_VIEW;
						}
						if (view != null) {
							this.viewAccessCache.put(cacheKey, view);
							this.viewCreationCache.put(cacheKey, view);
							if (logger.isTraceEnabled()) {
								logger.trace("Cached view [" + cacheKey + "]");
							}
						}
					}
				}
			}
			return (view != UNRESOLVED_VIEW ? view : null);
		}
	}

AbstractCachingViewResolver的createView

	protected View createView(String viewName, Locale locale) throws Exception {
		return loadView(viewName, locale);//调用实现类(子类UrlBasedViewResolver)的loadView的方法。而子类的loadVIew方法要去调用其实现类InternalResourceViewResolver的buildView()方法。
	}
	可能会被子类UrlBasedViewResolver .createView()调用

UrlBasedViewResolver .createView()方法

public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered

protected View createView(String viewName, Locale locale) throws Exception {
		//如果这个解析器不应该处理给定的视图,
		//返回NULL以传递到链中的下一个解析器。
		if (!canHandle(viewName, locale)) {
			return null;
		}
		// 检查特殊的“重定向:”前缀。
		if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
			String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
			RedirectView view = new RedirectView(redirectUrl,
					isRedirectContextRelative(), isRedirectHttp10Compatible());
			String[] hosts = getRedirectHosts();
			if (hosts != null) {
				view.setHosts(hosts);
			}
			return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
		}

		//检查特殊的“转发:”前缀
		if (viewName.startsWith(FORWARD_URL_PREFIX)) {
			String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
			return new InternalResourceView(forwardUrl);
		}

		// 否则返回到超类实现:调用loadView。
		return super.createView(viewName, locale);
	}

UrlBasedViewResolver .buildView()方法

protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		Class<?> viewClass = getViewClass();
		Assert.state(viewClass != null, "No view class");
//   viewClass  = class org.springframework.web.servlet.view.JstlView
		AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
		//Bea
		view.setUrl(getPrefix() + viewName + getSuffix());

		String contentType = getContentType();
		if (contentType != null) {
			view.setContentType(contentType);
		}

		view.setRequestContextAttribute(getRequestContextAttribute());
		view.setAttributesMap(getAttributesMap());

		Boolean exposePathVariables = getExposePathVariables();
		if (exposePathVariables != null) {
			view.setExposePathVariables(exposePathVariables);
		}
		Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
		if (exposeContextBeansAsAttributes != null) {
			view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
		}
		String[] exposedContextBeanNames = getExposedContextBeanNames();
		if (exposedContextBeanNames != null) {
			view.setExposedContextBeanNames(exposedContextBeanNames);
		}
//view = org.springframework.web.servlet.view.JstlView: unnamed; URL [/WEB-INF/jsp/index.jsp]
		return view;
	}

UrlBasedViewResolver的buildView返回的View对象
在这里插入图片描述

BeanUtil的instantiateClass()

  1. public static T instantiateClass(Class clazz) throws BeanInstantiationException

实例化一个类,使用它的“主”构造函数(对于Kotlin类,可能声明了默认参数)或它的默认构造函数(对于常规Java类,需要一个标准的无Arg设置)。注意,如果给定不可访问(即非公共)构造函数,此方法将尝试设置可访问的构造函数。

/**
实例化一个类,使用它的“主”构造函数(对于Kotlin类,可能声明了默认参数)或它的默认构造函数(对于常规Java类,需要一个标准的无Arg设置)。注意,如果给定不可访问(即非公共)构造函数,此方法将尝试设置可访问的构造函数。
	 * @param clazz 要实例化的类。
	 * @return  新实例
如果未找到主/默认构造函数,则可能指示{@link NoSuchMethodException}、在出现不可解析类定义的情况下{@link NoClassDefoundError}或其他{@link LinkageError}(例如,由于运行时缺少依赖关系),或从构造函数调用本身引发的异常。@参见Constructor#newInstance
	 */

//调用BeanUtil工具类的instantiateClass(参数class org.springframework.web.servlet.view.JstlView)
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
		Assert.notNull(clazz, "Class must not be null");
		if (clazz.isInterface()) {
			throw new BeanInstantiationException(clazz, "Specified class is an interface");
		}

		try {
		// 这里KotlinDetector.isKotlinType(clazz)的结果是false
// clazz.getDeclaredConstructor()   =	public org.springframework.web.servlet.view.JstlView()
			Constructor<T> ctor = (KotlinDetector.isKotlinType(clazz) ?
					KotlinDelegate.getPrimaryConstructor(clazz) : clazz.getDeclaredConstructor());
			return instantiateClass(ctor);
	//		ctor 的值public org.springframework.web.servlet.view.JstlView()
		}
		catch (NoSuchMethodException ex) {
			throw new BeanInstantiationException(clazz, "No default constructor found", ex);
		}
		catch (LinkageError err) {
			throw new BeanInstantiationException(clazz, "Unresolvable class definition", err);
		}
	}
  1. public static T instantiateClass(Constructor ctor, Object… args) throws BeanInstantiationException {
/**
*使用给定构造函数实例化类的方便方法。注意,如果给定了*不可访问(即非公共)构造函数,
此方法将尝试设置可访问的构造函数,并支持带有可选参数和默认值的Kotlin类*。
	 * @param ctor 要实例化的构造函数。
	 * @param args 要应用的构造函数参数
   (对于具有可选参数和默认值的Kotlin类,需要时对未指定的参数使用{@code NULL})
	 * @return 新的实例
	 * @throws BeanInstantiationException if the bean cannot be instantiated
	 * @see Constructor#newInstance
	 */
	public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
			//使用到下边的ReflectionUtils工具类,确保构造器是一个public构造器
			return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
					KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
//KotlinDetector.isKotlinType(ctor.getDeclaringClass()) 				flase
//这里执行的是ctor.newInstance(args)


		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
		}
	}

ReflectionUtils工具类

package org.springframework.util;
import org.springframework.lang.Nullable;
/**
 *用于使用反射API和处理的简单实用程序类
 * 仅供内部使用
 */
public abstract class ReflectionUtils {

  @SuppressWarnings("deprecation")  // on JDK 9
	public static void makeAccessible(Constructor<?> ctor) {
//判断构造器是否是public的
    if (
    (
    !Modifier.isPublic(ctor.getModifiers())    //false
     ||
		!Modifier.isPublic(ctor.getDeclaringClass().getModifiers())//false
    )
    &&
     !ctor.isAccessible()//!ctor.isAccessible()
     ) {
			ctor.setAccessible(true);
		}
	}
}

InternalResourceViewResolver

这个类是视图解析器最后的子类,其父类会调用buildView方法。但是这个buildView
这个方法最终实现又是在其父类UrlBasedViewResolver实现的

public class InternalResourceViewResolver extends UrlBasedViewResolver {
	
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		InternalResourceView view = (InternalResourceView) super.buildView(viewName);
		if (this.alwaysInclude != null) {
			view.setAlwaysInclude(this.alwaysInclude);
		}
		view.setPreventDispatchLoop(true);
		return view;
	}

调用父类的buildView()返回的View加以判断和修饰返回的View如下
在这里插入图片描述

这里插几个和context有关的类

AbstractRefreshableApplicationContext类

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;

/*
这里返回的对象信息是
this.beanFactory= org.springframework.beans.factory.support.DefaultListableBeanFactory
*/

		}
	}
}

变量对象的信息如下
在这里插入图片描述

AbstractApplicationContext类

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        /*如果已经可用,则将上下文的内部bean工厂返回为AutoireCapableBeanFactory。
         */
        @Override
        public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
        	return getBeanFactory();
        }

AbstractAutowireCapableBeanFactory initializeBean返回的包装Bean

在这里插入图片描述
返回设置号的View对象

View result = applyLifecycleMethods(viewName, view);

综上所述:最后返回的View对象就是一个设置好的JSTL视图对象
从dispatchServlet解析视图的方法出发到调用createView到各个视图解析器的createView方法。最后就是返回了一个View对象,至此dispatchServlet的视图已经创建完毕。

View view = viewResolver.resolveViewName(viewName, locale)

下一步,如果视图不为空,存储进入缓存。

					if (view != null) {
							this.viewAccessCache.put(cacheKey, view);
							this.viewCreationCache.put(cacheKey, view);
							if (logger.isTraceEnabled()) {
								logger.trace("Cached view [" + cacheKey + "]");
							}

2019/2/5
这一部分的开始
视图和model的结合渲染,其实就是将模型中的数据取出然后设置到request的attribute里边,设置好request的dispatch路径,然后使用forward进行转发。就和Servlet的转发一样的道理
在这里插入图片描述
这里调用dispatchServlet的render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
这个render方法又会调用AbstractView 的render方法

AbstractView 类

public abstract class AbstractView extends WebApplicationObjectSupport implements View, BeanNameAware{
//准备给定指定模型的视图,必要时将其与静态属性和RequestContext属性合并。
//为实际呈现委托给renderMergedOutputModel。
	public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
	if (logger.isTraceEnabled()) {
			logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
				" and static attributes " + this.staticAttributes);
		}
		 /*
		建包含动态值和静态属性的组合输出映射(从不{@Codenull})。动态值优先于静态	属性。
		*/
	Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
	/*准备渲染所需的响应。默认实现在通过HTTPS发送下载内容时为IE错误应用解决方案*/
		prepareResponse(request, response);
		/*子类必须实现此方法才能实际呈现视图。
		第一步是准备请求:在JSP中,这意味着将模型对象设置为请求属性。
		第二步是视图的实际呈现,例如,通过RequestDispatcher包括JSP。
		*/
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}
}
  • createMergedOutputModel方法
    返回的model在这里插入图片描述
 /*
建包含动态值和静态属性的组合输出映射(从不{@Codenull})。动态值优先于静态	属性。
*/
protected Map<String, Object> createMergedOutputModel(@Nullable Map<String, ?> model,
			HttpServletRequest request, HttpServletResponse response) {

		@SuppressWarnings("unchecked")
		Map<String, Object> pathVars = (this.exposePathVariables ?
				(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);
		// 合并静态和动态模型属性。
		int size = this.staticAttributes.size();
		size += (model != null ? model.size() : 0);
		size += (pathVars != null ? pathVars.size() : 0);

		Map<String, Object> mergedModel = new LinkedHashMap<>(size);
		mergedModel.putAll(this.staticAttributes);
		if (pathVars != null) {
			mergedModel.putAll(pathVars);
		}
		if (model != null) {
			mergedModel.putAll(model);
		}

		// 公开RequestContext?
		if (this.requestContextAttribute != null) {
			mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
		}

		return mergedModel;
	}
  • prepareResponse
    /**
    准备渲染所需的响应。默认实现在通过HTTPS发送下载内容时为IE错误应用解决方案。
    */
    protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
    if (generatesDownloadContent()) {
    response.setHeader(“Pragma”, “private”);
    response.setHeader(“Cache-Control”, “private, must-revalidate”);
    }
    }

  • renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);

	/**
根据指定的模型呈现内部资源。*这包括将模型设置为请求属性。
	 */
protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 将模型对象公开为请求属性。其实就是往request里边设置对应的属性值和属性名
		exposeModelAsRequestAttributes(model, request);

		// 将帮助程序公开为请求属性(如果有的话)。
		exposeHelpers(request);

		// 确定请求分派器的路径。
		/*
prepateForRendering()

准备呈现,并确定要转发(或包括)的请求分派程序路径。此实现只返回配置的URL。子类可以重写它以确定要呈现的资源,通常以不同的方式解释URL。返回
/WEB-INF/jsp/index.jsp
*/
		String dispatcherPath = prepareForRendering(request, response);// 确定请求分派器的路径。

		// 获取目标资源(通常是JSP)的RequestDispatcher。
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// 如果已经包含或响应已经提交,执行包含,其他转发。
		if (useInclude(request, response)) {
		/**useinclude()
确定是使用RequestDispatcher的{@code include}还是*{@code Forward}方法。
执行检查是否在请求中找到包含URI属性,指示包含请求,以及响应是否已提交。在这两种情况下,都将执行包含,因为转发不再可能。
*/
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(request, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.forward(request, response);
		}
	}

需要解释的方法

获取要公开给{@link#renderMergedOutputModel}的请求句柄,即视图。默认实现将Springbean公开的原始请求包装为请求属性(如果需要的话)。
	protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) {
		if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) {
			WebApplicationContext wac = getWebApplicationContext();
			Assert.state(wac != null, "No WebApplicationContext");
			return new ContextExposingHttpServletRequest(originalRequest, wac, this.exposedContextBeanNames);
		}
		return originalRequest;
	}

request.getRequestDispatcher(path)
在这里插入图片描述
渲染完则会进行拦截器afterComplete的部分

mappedHandler.triggerAfterCompletion(request, response, null);
//在映射的HandlerInterceptor上触发Completion回调。
//将只对所有已成功完成并返回true的PreHandle调用的拦截器调用Completion。

补充:

返回modelAndView的方法;

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这个是handleradapter的方法。传入的参数是request,response,和执行链对象的handler对象。

ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

配置的实现类:
在这里插入图片描述
在这里插入图片描述

一些方法声明和实现在抽象类AbstractHandlerMethodAdapter里边,还有一些需要实现HandlerAdapter类要求的方法被包装了,比如handle方法,在handle方法的实现上引用了另外一个方法的实现,这种设计模式忘记叫啥了
这个handleradapter接口的三个必要方法声明以及我的注释

@Override
	public boolean supports(Object handler) {
	//判断该handler是否是HttpRequestHandler的一个实例
	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	//内部再调用HttpRequestHandler的handleRequest的方法处理响应和请求。
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
}

实现类RequestMappingHandlerAdapter的部分代码

package org.springframework.web.servlet.mvc.method.annotation;

import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
import org.springframework.web.util.WebUtils;
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}
}

这个方法又是调用了invokeHandlerMethod这个方法来返回ModelAndView的

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;
			//handler类的主要处理请求方法,所有handler必须实现这个接口并且实现这个方法
			//这里的都Dispatch的调用是mappedHandler.getHandler(),这个就是那个映射的那个方法。

}

ModelAndView的对象信息

在这里插入图片描述
ModelAndView对象

public class ModelAndView {

	/** View instance or view name String */
	@Nullable
	private Object view;
	/** Model Map */
	@Nullable
	private ModelMap model;
	/** Optional HTTP status for the response */
	@Nullable
	private HttpStatus status;

ModelMap类

public class ModelMap extends LinkedHashMap<String, Object> {
	public ModelMap() {
	}
	public ModelMap(String attributeName, @Nullable Object attributeValue) {
		addAttribute(attributeName, attributeValue);
	}

	public ModelMap(Object attributeValue) {
		addAttribute(attributeValue);
	}
	public ModelMap addAttribute(String attributeName, @Nullable Object attributeValue) {
		Assert.notNull(attributeName, "Model attribute name must not be null");
		put(attributeName, attributeValue);
		return this;
	}


	public ModelMap addAttribute(Object attributeValue) {
		Assert.notNull(attributeValue, "Model object must not be null");
		if (attributeValue instanceof Collection && ((Collection<?>) attributeValue).isEmpty()) {
			return this;
		}
		return addAttribute(Conventions.getVariableName(attributeValue), attributeValue);
	}


	public ModelMap addAllAttributes(@Nullable Collection<?> attributeValues) {
		if (attributeValues != null) {
			for (Object attributeValue : attributeValues) {
				addAttribute(attributeValue);
			}
		}
		return this;
	}


	public ModelMap addAllAttributes(@Nullable Map<String, ?> attributes) {
		if (attributes != null) {
			putAll(attributes);
		}
		return this;
	}


		public ModelMap mergeAttributes(@Nullable Map<String, ?> attributes) {
		if (attributes != null) {
			attributes.forEach((key, value) -> {
				if (!containsKey(key)) {
					put(key, value);
				}
			});
		}
		return this;
	}


	public boolean containsAttribute(String attributeName) {
		return containsKey(attributeName);
	}

}

View类


public interface View {

	String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
	String PATH_VARIABLES = View.class.getName() + ".pathVariables";

	String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
	@Nullable
	default String getContentType() {
		return null;
	}

	void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;

}

最终的那个视图JstlView

package org.springframework.web.servlet.view;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.MessageSource;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.support.JstlUtils;
import org.springframework.web.servlet.support.RequestContext;
/**
JSTL页面{@link InternalResourceView}的专门化,即使用JSP标准标记库的JSP页面。
<p>公开特定于
JSTL的请求属性,为JSTL的格式和消息标记指定locale和资源包,
使用Spring的locale和{@link org.Spring Frawork.context.MessageSource}。
{@link InternalResourceViewResolver}的典型用法如下所示,
从DispatcherServlet上下文定义的角度看:
<pre class="code">
 bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
 *   &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt;
 *   &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
 *   &lt;property name="suffix" value=".jsp"/&gt;
 * &lt;/bean&gt;
 *
 * &lt;bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"&gt;
 *   &lt;property name="basename" value="messages"/&gt;
 * &lt;/bean&gt;</pre>
*从处理程序返回的每个视图名称都将被转换为JSP*资源(例如:“MyView”->“/Web-INF/jsp/myView.jsp”),
使用*这个视图类启用显式的JSTL支持。
 *
*<p>指定的MessageSource在类路径中从“messages.properties”等
*文件中加载消息。这将自动以*JSTL本地化上下文的形式向视图公开,JSTLFMT标记(Message等)将使用该上下文。*考虑使用Spring的ReloadableResourceBundleMessageSource而不是*标准ResourceBundleMessageSource来进行更复杂的操作。
*当然,任何其他Spring组件都可以共享相同的MessageSource。
 *
这是一个单独的类,主要是为了避免*{@link InternalResourceView}本身中的JSTL依赖关系。直到J2EE1.4,
JSTL才成为标准*J2EE的一部分,因此我们不能假设JSTLAPIJAR在类路径上是可用的。
 *
<p>提示:将{@link#setExposeContextBeansAsAttributes}标志设置为“true”
*以便使应用程序上下文中的所有Springbean都可在JSTL表达式中访问*(例如,在{@code c:out}值表达式中)。
*这还将使所有这些bean都可以在JSP中的朴素{@code${.}*表达式中访问。
 *
 * @author Juergen Hoeller
 * @since 27.02.2003
 * @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext
 * @see InternalResourceViewResolver
 * @see org.springframework.context.support.ResourceBundleMessageSource
 * @see org.springframework.context.support.ReloadableResourceBundleMessageSource
 */
public class JstlView extends InternalResourceView {

	@Nullable
	private MessageSource messageSource;

	/**
	 * 构造函数,用作bean。
	 * @see #setUrl
	 */
	public JstlView() {
	}
	/**
	 * 构造函数,用于作为bean.create一个具有给定URL的新JstlView。
	 * @param url the URL to forward to
	 */
	public JstlView(String url) {
		super(url);
	}
	public JstlView(String url, MessageSource messageSource) {
		this(url);
		this.messageSource = messageSource;
	}
	/**
	用JSTL感知的MessageSource包装MessageSource,
  该消息源知道jstl的{@javax.servlet.jsp.jstl.fmt.localizationContext}代码
	 */
	@Override
	protected void initServletContext(ServletContext servletContext) {
		if (this.messageSource != null) {
			this.messageSource = JstlUtils.getJstlAwareMessageSource(servletContext, this.messageSource);
		}
		super.initServletContext(servletContext);
	}

	/**
	 * 公开Spring的locale和MessageSource的JSTL LocalizationContext。
	 * @see JstlUtils#exposeLocalizationContext
	 */
	@Override
	protected void exposeHelpers(HttpServletRequest request) throws Exception {
		if (this.messageSource != null) {
			JstlUtils.exposeLocalizationContext(request, this.messageSource);
		}
		else {
			JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));
		}
	}
}

EL表达式的使用

<br>
EL表达式接收:<br>
session值: ${loginflag}<br>
request值:<br>
用户名: ${user}<br>
密码: ${pass}
</body>
</html>

instanceof

Java中instanceof关键字的理解
java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。

时间仓促,知识水平有限,如果你想了解可以使用idea的调试。
调试常用快捷键
书签:ctrl+F11 或者Shift+F11或者按住ctrl+右击
Ctrl+Shift+F9,编译
Ctrl+Shift+F10,运行
Ctrl+Shift+F8,查看断点
通过Alt+F8查看变量在当前断点的当前值
F8,步过
F7,步入
Shift+F7,智能步入
Shift+F8,步出
Alt+Shift+F8,强制步过
Alt+Shift+F7,强制步入

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,可以通过实现WebMvcConfigurer接口来自定义DispatcherServlet。 首先,需要创建一个类实现WebMvcConfigurer接口,并实现addViewControllers方法。该方法可以用来添加自定义的ViewController,并指定响应的URL路径。例如: ```java @Configuration public class CustomWebMvcConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/custom").setViewName("custom"); } } ``` 上述代码中,我们定义了一个名为CustomWebMvcConfig的类,并通过@Configuration注解将其声明为Spring配置类。该类实现了WebMvcConfigurer接口,并重写了其中的addViewControllers方法。在该方法中,我们使用registry对象添加了一个名为/custom的ViewController,并将其对应的视图名称设置为custom。 接下来,我们需要在应用程序的入口类中添加一个ServletRegistrationBean来注册自定义的DispatcherServlet。例如: ```java @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } @Bean public ServletRegistrationBean<DispatcherServlet> dispatcherServlet() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(CustomWebMvcConfig.class); dispatcherServlet.setApplicationContext(applicationContext); ServletRegistrationBean<DispatcherServlet> servletRegistrationBean = new ServletRegistrationBean<>(dispatcherServlet, "/custom/*"); servletRegistrationBean.setName("customDispatcherServlet"); return servletRegistrationBean; } } ``` 上述代码中,我们通过@Bean注解创建了一个名为dispatcherServlet的方法。该方法返回一个ServletRegistrationBean对象,其中包含了自定义的DispatcherServlet和其对应的URL路径。在该方法中,我们创建了一个DispatcherServlet实例,并通过AnnotationConfigWebApplicationContext类指定了应用程序上下文。然后,将应用程序上下文设置为DispatcherServlet的上下文,并将其注册到ServletRegistrationBean中。最后,我们将ServletRegistrationBean的名称设置为customDispatcherServlet,并返回该对象。 这样,自定义的DispatcherServlet就注册成功了。可以通过访问http://localhost:8080/custom/来访问自定义的ViewController。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值