DispatcheServlet类图,我们根据其类图进行源码分析
GenericServlet 源码分析
/** * 定义一个通用的,协议无关的Servlet.如果需要编写一个在Web中使用的Http Severlet需要继承HttpServlet * GeneraicServlet实现了Servlet接口和ServletConfig接口。GenericServlet *可以直接通过Servlet扩展,虽然这是比较常见的一种是继承特殊协议的子类,如HttpServlet * GenericServlet使写Servlet变的更容易。它提供简单的版本的生命周期方法 init,destory和ServletCOnfig接口中的方法 * GenericServlet同样实现了生命在ServeltContext接口中的log方法s */ public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { private static final String LSTRING_FILE = "javax.servlet.LocalStrings"; private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE); private transient ServletConfig config; /** *无参构造方法 * */ public GenericServlet() { } /** * 被servlet容器调用,用来指示一个servlet正在停止服务 * */ public void destroy() { } /** * 返回一个命名的初始化参数的字符串值,如果这个初始化参数不存在则返回null * 这个方法对从ServletConfig对象中获指定名称的参数的值提供了便利 */ public String getInitParameter(String name) { //获取ServletConfig对象 ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException( lStrings.getString("err.servlet_config_not_initialized")); } // 从servletConfig中获取指定名称初始化参数值 return sc.getInitParameter(name); } /** * 将所有参数名称作为一个Enumeration<String>返回。如果没有初始化参数则返回一个空的Enumration */ public Enumeration<String> getInitParameterNames() { //获取servletConfig对象 ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException( lStrings.getString("err.servlet_config_not_initialized")); } //获取参数名称的枚举 return sc.getInitParameterNames(); } /** * 获取一个ServletConfig对象 */ public ServletConfig getServletConfig() { return config; } /** *返回一个servlet正在其中运行的ServletContext的引用 * * */ public ServletContext getServletContext() { ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException( lStrings.getString("err.servlet_config_not_initialized")); } return sc.getServletContext(); } /** *返回一个关于serlvet信息,比如 *作者,版本以及版权等。默认情况下,这个方法返回一个空字符串。如果需要返回有意义的值需要重写这个方法 * */ public String getServletInfo() { return ""; } /** * 被Servlet容器调用,用来标示一个servlet正准备开始服务。在该方法中将 * * ServletConfig赋值给属性config后调用init()方法 */ public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } /** * 初始化处理,具体处理过程延迟到子类 **/ public void init() throws ServletException { } public void log(String msg) { getServletContext().log(getServletName() + ": "+ msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } /** * 被servlet容器调用,让一个servlet响应一个请求 * 这是一个抽象方法,所以子类比如HttpServlet必须重写这个方法 */ public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; /** * 返回servlet实例的名称 */ public String getServletName() { ServletConfig sc = getServletConfig(); if (sc == null) { throw new IllegalStateException( lStrings.getString("err.servlet_config_not_initialized")); } return sc.getServletName(); } }
HttpServlet 源码分析
/** * 提供了一个抽象类用来被继承创建一个Http servlet来使用一个web站点。 * 一个HttpServlet的子类必须至少重写下述中的一个方法 * doGet,如果servlet支持Http get请求 * doPost,支持http post请求 * doPut, 支持http put请求 * doDelete 支持http delete请求 * init 和destroy 来管理servlet声明周期资源 * getServletInfo,servlet用来提供自身信息 * 几乎没有理由去重写service方法。service方法处理标准的Http请求时通过将其分发给相应请求类型的处理方法。 * Servlet通常运行在多线程服务器上,所以必须注意一个servlet必须处理并发请求,同时谨慎地同步访问共享资源。 * 共享资源包括内存数据例如 实例或类变量和外部对象如文件,数据库连接,网络连接 * */ public abstract class HttpServlet extends GenericServlet { private static final String METHOD_DELETE = "DELETE"; private static final String METHOD_HEAD = "HEAD"; private static final String METHOD_GET = "GET"; private static final String METHOD_OPTIONS = "OPTIONS"; private static final String METHOD_POST = "POST"; private static final String METHOD_PUT = "PUT"; private static final String METHOD_TRACE = "TRACE"; private static final String HEADER_IFMODSINCE = "If-Modified-Since"; private static final String HEADER_LASTMOD = "Last-Modified"; private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings"; private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE); /** *无参构造方法 * */ public HttpServlet() { } /** * 服务器通过service方法调用处理一个Http的get请求 * 重写这个方法支持get请求同时也自动支持Http Head请求。Head请求是一个响应中没有返回体,只有请求头部字段 */ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } /** * 返回HttpServletRequest对象的最后修改时间 */ protected long getLastModified(HttpServletRequest req) { return -1; } protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { NoBodyResponse response = new NoBodyResponse(resp); //委托给doGet方法 doGet(req, response); response.setContentLength(); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_post_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_put_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_delete_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } private Method[] getAllDeclaredMethods(Class<?> c) { if (c.equals(javax.servlet.http.HttpServlet.class)) { return null; } Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); Method[] thisMethods = c.getDeclaredMethods(); if ((parentMethods != null) && (parentMethods.length > 0)) { Method[] allMethods = new Method[parentMethods.length + thisMethods.length]; System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length); System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length); thisMethods = allMethods; } return thisMethods; } /** * 从公开的service方法中接收标准的HTTP请求,将其分发给相应的处理方法。 */ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求方法 String method = req.getMethod(); // 如果是get方法 if (method.equals(METHOD_GET)) { //获取最后修改时间 long lastModified = getLastModified(req); // 如果最后修改时间未知 if (lastModified == -1) { //分发给doGet方法处理 doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); // 如果servlet最后修改时间小于请求的最后修改时间则调用doGet,否则返回304 if (ifModifiedSince < lastModified) { maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { //没有支持的处理方法,返回一个错误响应 String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } /* * Sets the Last-Modified entity header field, if it has not * already been set and if the value is meaningful. Called before * doGet, to ensure that headers are set before response data is * written. A subclass might have set this header already, so we * check. */ private void maybeSetLastModified(HttpServletResponse resp, long lastModified) { if (resp.containsHeader(HEADER_LASTMOD)) return; if (lastModified >= 0) resp.setDateHeader(HEADER_LASTMOD, lastModified); } /** * 将请求委托给给protected void service(HttpServletRequest req, HttpServletResponse resp) */ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); } request = (HttpServletRequest) req; response = (HttpServletResponse) res; service(request, response); } } }
HttpServletBean
public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware { protected final Log logger = LogFactory.getLog(getClass()); /** * 一组必须为这个servlet提供的配置参数 */ private final Set<String> requiredProperties = new HashSet<String>(); private Environment environment = new StandardServletEnvironment(); /** * 强制子类调用这个方法来指定属性,并且必须提供作为作为配置参数。这个方法应该在子类的构造方法中调用y */ protected final void addRequiredProperty(String property) { this.requiredProperties.add(property); } /** * 映射配置参数到这个Servlet bean的书zing同时调用子类的初始化方法 */ @Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // 使用初始化参数设置bean的属性 try { //创建一个ServletConfigPropertyValues对象 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); //获取当前对象的BeanWrapper,使用JavaBean风格访问bean的属性 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); //创建一个ServletContextResourceLoader ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); // 设置bw的属性编辑器 bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment)); //初始化当前对象的BeanWrapper initBeanWrapper(bw); //设置bean属性 bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } //调用子类初始化方法 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } } /** * 对初始化BeanWrapper,可以使用自定义属性编辑器 * 默认实现是一个空方法 */ protected void initBeanWrapper(BeanWrapper bw) throws BeansException { } /** * 重写方法,如果没有servletConfig 则返回null */ @Override public final String getServletName() { return (getServletConfig() != null ? getServletConfig().getServletName() : null); } @Override public final ServletContext getServletContext() { return (getServletConfig() != null ? getServletConfig().getServletContext() : null); } /** *子类通过重写这个方法实现自定义的初始化,在这个方法调用之前,这个Servlet所有bean属性都已经设置好了 */ protected void initServletBean() throws ServletException { } public void setEnvironment(Environment environment) { this.environment = environment; } /** * 从的ServletConfig初始化参数创建PropertyValues。 */ private static class ServletConfigPropertyValues extends MutablePropertyValues { /** * 创建一个新的ServeltConfigPropertyValues */ public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties) throws ServletException { //获取所有丢失的参数 Set<String> missingProps = (requiredProperties != null && !requiredProperties.isEmpty()) ? new HashSet<String>(requiredProperties) : null; // 获取所有初始化参数名枚举 Enumeration en = config.getInitParameterNames(); //遍历所有初始化参数 while (en.hasMoreElements()) { String property = (String) en.nextElement(); Object value = config.getInitParameter(property); //添加到property数组中 addPropertyValue(new PropertyValue(property, value)); if (missingProps != null) { missingProps.remove(property); } } // 如果依然有丢失的属性则抛出异常 if (missingProps != null && missingProps.size() > 0) { throw new ServletException( "Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", ")); } } } }
FrameworkServlet
/** * Spring's web框架的Servlet基类。提供在一个基于JavaBean集成Spring应用上下文的解决方案 * 这个类提供了如下功能: * 管理每个Servlet的WebApplicationContext实例。servlet的配置servlet命名空间中的bean由决定 * 发布请求处理事件,不论请求是否被成功处理 publishEvents=true,默认为true * 子类必须实现doService方法去处理请求。因为这个类继承HttpeServletBean类而不是直接继承HttpServlet类, * 子类可以重写initFrameworkServlet来自定义初始化 * 在servlet初始化参数中检测contextClass并将其设置为默认的上下文类,如果没有找到则使用XmlWEbApplicationContext.一般都是使用默认值 * 注意,默认情况下自定义的上下文类需要实现ConfigurableWebApplicationContext接口。 * 接受一个可选参的servelt初始化参数contextInitializerClassers指定一个或多个ApplicationContextInitializer;托管的WebApplicationContext会 * 委托给这些指定的初始化器增加一些额外的程序化配置。 * ContextLoader也支持具有相同语义的contextInitializerClassers上线文参数,对根上下文进行程序化配置。 * 传递servlet初始化配置参数contextConfigLocation到上下文中,解析成潜在可以通过逗号空格分割的多文件路径, * 例如“test-servlet.xml,myServlet.xml” * 如果没有明确指明contextConfigLocation,则从servlet命名空间中加载默认的路径的配置文件 * 需要注意的是:在配置多个路径时,后面Bean中定义将覆盖前一个加载文件中的配置,至少Spring默认ApplicationContext实现是这么处理的。 * 默认的命名空间是servletName-servlet,例如test-servlet, servlet的名称就是test, * XmlWebApplication默认的加载路径是/WEB-INF/test-servlet.xml * */ @SuppressWarnings("serial") public abstract class FrameworkServlet extends HttpServletBean { /** * *WebApplicationContext命名空间的后缀。如果一个servlet在这个类的上下文中给定的名字是“test”,这个servlet的命名空间则使**用test-servelt */ public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet"; /** *FrameworkServlet默认的上下文 */ public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class; /** * WebApplicationContext在servlet 上下文中属性名称的前缀。最后. */ public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT."; /** * 在一个初始化参数的多个值之间使用分割符分割 * */ private static final String INIT_PARAM_DELIMITERS = ",; \t\n"; /** */ private String contextAttribute; /** WebApplicationContext实现类 */ private Class<?> contextClass = DEFAULT_CONTEXT_CLASS; /** WebApplicationContext的Id*/ private String contextId; /** 当前servlet的命名空间 */ private String namespace; /** 上下文配置路径 */ private String contextConfigLocation; /** 是否将WebApplicationContext发布为Servlet上下文的一个属性。默认是true */ private boolean publishContext = true; /** 是否在每个请求结束发布一个ServletRequestHandledEvent */ private boolean publishEvents = true; /** Expose LocaleContext and RequestAttributes as inheritable for child threads? */ private boolean threadContextInheritable = false; /** 是否分发Http opetion请求 */ private boolean dispatchOptionsRequest = false; /** 是否分发http trace请求 */ private boolean dispatchTraceRequest = false; /**当前servlet的WebApplicationContext */ private WebApplicationContext webApplicationContext; /** 标志onFreash方法是否已经被调用过*/ private boolean refreshEventReceived = false; /** Comma-delimited ApplicationContextInitializer classnames set through init param */ private String contextInitializerClasses; /** Actual ApplicationContextInitializer instances to apply to the context */ private ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>(); public FrameworkServlet() { } public FrameworkServlet(WebApplicationContext webApplicationContext) { this.webApplicationContext = webApplicationContext; } // setter and getter /** * 重写HttpServletBean的方法,在所有属性设置完成后调用,创建当前servlet的WebApplicationContext */ @Override protected final void initServletBean() throws ServletException { //记录日志 getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); if (this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); } long startTime = System.currentTimeMillis(); try { //初始化webApplicationContext this.webApplicationContext = initWebApplicationContext(); //初始化FrameworkServlet initFrameworkServlet(); } catch (ServletException ex) { this.logger.error("Context initialization failed", ex); throw ex; } catch (RuntimeException ex) { this.logger.error("Context initialization failed", ex); throw ex; } if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } } /** * 初始化WebApplicationContext */ protected WebApplicationContext initWebApplicationContext() { //获取根WebApplicationContext WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; // 如果一个上下文对象已经在构造方法中创建则直接使用 if (this.webApplicationContext != null) { wac = this.webApplicationContext; //如果web应用上下文是ConfiguableWebApplicontionContext if (wac instanceof ConfigurableWebApplicationContext) { // 强制类型转换 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; //如果上下文不是活跃的,即上线问没有被刷新 if (!cwac.isActive()) { // 如果没有父上下文对象,则将根上下文设置为父上下文 if (cwac.getParent() == null) { cwac.setParent(rootContext); } //配置同时刷新上下文 configureAndRefreshWebApplicationContext(cwac); } } } //如果在构造方法中没有注入上下文,则在servlet上下文中找到一个已经注册的上下文。 if (wac == null) { wac = findWebApplicationContext(); } if (wac == null) { // 如果当前servlet没有定义上下文对象则创建一个本地webApplicationContext wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { onRefresh(wac); } if (this.publishContext) { //将上下文发布为一个servlet上下文属性 // 获取属性名称 String attrName = getServletContextAttributeName(); //将其设置为servlet上下文的一个属性 getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; } /** * */ protected WebApplicationContext findWebApplicationContext() { //获取上下文属性名称 String attrName = getContextAttribute(); // 如果属性名称为null则返回null if (attrName == null) { return null; } // 从servlet 上下文中获取Web应用上下文 WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName); // 如果web应用上下文为null则抛出一个异常,否则返回这个上下文 if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: initializer not registered?"); } return wac; } /** *穿件一个新的WebApplicaitonContext对象 */ protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } // 如果web应用上下文类不是ConfigurableWebApplicationContext类或其子类则抛出一个异常 if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } // 创建一个ConfiguableWebApplicaitonContext对象 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); // 设置父上下文 wac.setParent(parent); //设置配置资源路径 wac.setConfigLocation(getContextConfigLocation()); // 刷新 configureAndRefreshWebApplicationContext(wac); //返回上下文对象 return wac; } protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // 如果当前contextId不为null则将web应用上下文的Id设置为contextId if (this.contextId != null) { wac.setId(this.contextId); } else { // 获取servlet上下文对象 ServletContext sc = getServletContext(); // 如果Servlet版本小于2.5,如果web.xml中配置servlet名称则使用其作为上下文的ID if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { // 获取servlet上下文名称 String servletContextName = sc.getServletContextName(); // 如果servetContextName不为null则使用其构建一个Id并设置为WebApplicationContext的ID if (servletContextName != null) { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName + "." + getServletName()); } else { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getServletName()); } } else { // servlet2.5 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName()); } } } //设置servletContext wac.setServletContext(getServletContext()); // 设置servletConfig wac.setServletConfig(getServletConfig()); // 设置nameSpace wac.setNamespace(getNamespace()); //设置监听器 wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); //后置处理 postProcessWebApplicationContext(wac); applyInitializers(wac); wac.refresh(); } protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { return createWebApplicationContext((ApplicationContext) parent); } /** * 在WebApplicationContext被刷新前,委派给在当前servlet初始化参数init-param中指定的contextInitializerClasses 类处理 */ @SuppressWarnings("unchecked") protected void applyInitializers(ConfigurableApplicationContext wac) { if (this.contextInitializerClasses != null) { String[] initializerClassNames = StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS); for (String initializerClassName : initializerClassNames) { ApplicationContextInitializer<ConfigurableApplicationContext> initializer; try { Class<?> initializerClass = ClassUtils.forName(initializerClassName, wac.getClassLoader()); initializer = BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class); } catch (Exception ex) { throw new IllegalArgumentException( String.format("Could not instantiate class [%s] specified via " + "'contextInitializerClasses' init-param", initializerClassName), ex); } this.contextInitializers.add(initializer); } } Collections.sort(this.contextInitializers, new AnnotationAwareOrderComparator()); for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) { initializer.initialize(wac); } } protected void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac) { } public String getServletContextAttributeName() { return SERVLET_CONTEXT_PREFIX + getServletName(); } public final WebApplicationContext getWebApplicationContext() { return this.webApplicationContext; } protected void initFrameworkServlet() throws ServletException { } /** * 刷新web应用上下文对象 */ public void refresh() { WebApplicationContext wac = getWebApplicationContext(); if (!(wac instanceof ConfigurableApplicationContext)) { throw new IllegalStateException("WebApplicationContext does not support refresh: " + wac); } ((ConfigurableApplicationContext) wac).refresh(); } /** *应用上下文刷新事件监听器回调方法 */ public void onApplicationEvent(ContextRefreshedEvent event) { this.refreshEventReceived = true; onRefresh(event.getApplicationContext()); } /** *模板方法模式,具体的处理逻辑延迟到子类中 */ protected void onRefresh(ApplicationContext context) { // For subclasses: do nothing by default. } /** * Http请求的具体处理方法 **/ protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取当前时间 long startTime = System.currentTimeMillis(); Throwable failureCause = null; // 获取目前线程持有的LocalContext. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); //将localContext和当前线程关联 LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable); //获取当前线程持有的RequestAttributes RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = null; // 如果当前线程没有持有RequestAttributes对象或者持有对象的是ServletReqeustAttributes则创建一个新的ServletREquestAttributes if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) { requestAttributes = new ServletRequestAttributes(request); //与当前线程关联 RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); } if (logger.isTraceEnabled()) { logger.trace("Bound request context to thread: " + request); } try { // 将请求委托给子类的doService方法处理 doService(request, response); } catch (ServletException ex) { failureCause = ex; throw ex; } catch (IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { // 清除请求同时复位线程上下文 LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable); //复位RequestAttributes if (requestAttributes != null) { RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable); requestAttributes.requestCompleted(); } if (logger.isTraceEnabled()) { logger.trace("Cleared thread-bound request context: " + request); } if (logger.isDebugEnabled()) { if (failureCause != null) { this.logger.debug("Could not complete request", failureCause); } else { this.logger.debug("Successfully completed request"); } } // 如果需要发布一个请求处理完成的事件则发送该事件 if (this.publishEvents) { // Whether or not we succeeded, publish an event. long processingTime = System.currentTimeMillis() - startTime; //发布一个ServeltReqeustHandledEvent事件,用户可以对该事件进行监听 this.webApplicationContext.publishEvent( new ServletRequestHandledEvent(this, request.getRequestURI(), request.getRemoteAddr(), request.getMethod(), getServletConfig().getServletName(), WebUtils.getSessionId(request), getUsernameForRequest(request), processingTime, failureCause)); } } } protected LocaleContext buildLocaleContext(HttpServletRequest request) { return new SimpleLocaleContext(request.getLocale()); } protected String getUsernameForRequest(HttpServletRequest request) { Principal userPrincipal = request.getUserPrincipal(); return (userPrincipal != null ? userPrincipal.getName() : null); } /** * 模板方法模式,将具体实现延迟到子类中 **/ protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception; /** * 关闭应用上下文 */ @Override public void destroy() { getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'"); if (this.webApplicationContext instanceof ConfigurableApplicationContext) { ((ConfigurableApplicationContext) this.webApplicationContext).close(); } } /** * 应用上下文监听器 */ private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> { public void onApplicationEvent(ContextRefreshedEvent event) { // FrameworkServlet.this.onApplicationEvent(event); } } }
相关推荐
本文将深入探讨如何使用这些技术实现DispatchServlet,并结合省市级联的功能。 首先,Spring MVC是Spring框架的一部分,它是一个用于构建Web应用程序的模型-视图-控制器(MVC)架构。DispatchServlet是Spring MVC的...
Spring MVC的DispatcherServlet是整个框架的核心组件,它作为前端控制器,负责接收HTTP请求,并调度相应的处理器来处理这些请求。在本文中,我们将深入探讨DispatcherServlet的实现机制。 首先,DispatcherServlet...
SpringMVC 学习笔记涵盖了从基础到高级的多个方面,如源码分析、实例代码、Maven 配置、Web.xml 配置以及注解驱动的编程。对于初学者来说,理解 SpringMVC 的工作流程至关重要。SpringMVC 的工作流程通常始于浏览器...
* Web 服务器解析请求 URL 并去匹配 DispatchServlet 的映射 URL * 如果匹配上就将这个请求放入到 DispatchServlet * DispatchServlet 根据 Mapping 配置去寻找相应的 Handle * Handle 封装了处理业务逻辑的代码 * ...
SpringMVC 是一个基于 DispatchServlet 的分层控制框架。客户端发出 HTTP 请求,Web 服务器解析 URL 并将请求转发给 DispatchServlet,DispatchServlet 根据映射配置找到对应的 Handler,Handler 封装了业务逻辑代码...
由于我们日常工作中都是在现有框架下...3.指出了微服务是如何实现提供外部服务的能力-通过创建Tomcat容器,绑定并监听服务端口,不断拉取请求并结合DispatchServlet的映射关系找到真正提供服务的方法,处理请求并返回。
在Spring MVC框架中,DispatchServlet扮演着至关重要的角色。它是一个前端控制器,负责接收HTTP请求并分发到相应的处理器。在web.xml配置文件中,DispatchServlet通常被映射为"/",这意味着任何到达应用程序的URL...
闲来无事,手写Spring的mini版本 1.0, 目前只有几个核心功能, @Controller,@RequestMapping,@RequestParam,HandlerMapping,DispatchServlet等.但是从前端发起URL请求到后台可以处理结果并且返回, 实现了...
在开发Java项目时,Maven是一个非常重要的构建工具,它帮助我们管理依赖、构建项目以及自动化测试。然而,有时候在使用Maven进行打包操作时,可能会遇到各种问题。本篇文章将详细阐述如何解决Maven打包出错的问题,...
Springboot 2.4.4 网上搜到的配置多个DispatcherServlet 都有坑,自己避坑写的一个demo,处理.do .htm请求,Controller分离不会出现一个Controller可以处理.do也处理.htm可自己扩展.action .json等,适合分离前台...
本文基于Java的OA办公管理系统在分析设计时遵循软件工程的思想,文中详细阐述了系统需求分析、系统设计、数据库设计、系统实现以及系统测试五方面。系统运用JSP+Spring+SpringMVC+Mybatis技术的整合进行系统的开发,...
例如,`DispatchServlet`可能会使用RequestDispatcher找到并调用相应的业务逻辑,这可能是另一个内部定义的Servlet,或者是一个Action类。 在MVC模式中,Model负责数据管理,View负责渲染用户界面,而Controller...
该问题主要是由于在 DispatchServlet 中没有正确配置拦截器和跨域请求的设置所致。 在解决该问题时,可以通过在 DispatchServlet 中添加拦截器来解决webSocket请求问题。此外,需要在配置访问地址时设置连接的域名...
后台整合包精简版(servlet_DBC)是一个整合了部分Java后台功能的工具包。修复了部分问题,增加了一些功能;...继承dispatchservlet可以更方便使用request和response;使用更新对象可以用dbctools获取回填主键;
- **选项分析**: - **a. 保证每一层的感受野不变,网络深度加深,使得网络的精度更高**:正确。Inception模块通过使用不同大小的卷积核(如1×1、3×3、5×5等),能够在保持感受野大小不变的情况下增加网络的深度...
使用spring+springmvc+hibernate的方式整合的sshDemo,主要用于学习整合框架,新工程的创建模板。与旧版sshDemo相比,修订了dispatchServlet的配置,增加了springmvc默认静态资源配置,更好的配置系统首页
MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。 Tomcat Tomcat是Apache下的一个开源的...
简单登录例子,然后进行偶像投票选择,输入偶像年龄做了加1操作,讲解的是springMVC框架的登入功能的实现,首先我们应该知道springMVC框架是怎么进行业务转发的 这里的DispatchServlet是springmvc的Servlet,所有的...
在Spring的源码层面,IoC(控制反转)的原理是通过依赖注入来实现的,它将程序中的依赖关系的管理从程序代码中抽取出来,以配置文件的形式进行管理。SpringBean的生命周期涉及一系列步骤,包括初始化前、初始化后、...