概述
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()
- 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);
}
}
- 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">
* <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
* <property name="prefix" value="/WEB-INF/jsp/"/>
* <property name="suffix" value=".jsp"/>
* </bean>
*
* <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
* <property name="basename" value="messages"/>
* </bean></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,强制步入
最后
以上就是仁爱草莓为你收集整理的一次调试dispatcherServlet的全部内容,希望文章能够帮你解决一次调试dispatcherServlet所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复