springmvc 之DispatcherServlet初始化
来源:互联网 发布:黄皮书和考研真相 知乎 编辑:程序博客网 时间:2024/06/05 05:38
ContextLoaderListener 只是辅助功能,用于创建WebApplicationContext类型实例,真正的逻辑实现其实在DispatcherServlet中进行,DispatcherServlet实现了servlet。servlet的生命周期是由servlet容器控制。分为3个阶段:初始化、运行、销毁
DispatcherServlet的初始化
在父类HttpServletBean中找到该方法
@Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } try { // 解析init-param并封装到pvs中 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); //将当前servlet转为BeanWrapper,从而能够以Spring的方式来对init-param的值进行注入 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); //注册自定义属性编辑器,一旦遇到Resouce类型的属性将会使用ResourceEditor进行解析 bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); //模版设计模式,留给子类覆盖 initBeanWrapper(bw); 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"); } }
servletBean的初始化
在ContextloaderListener加载的时候已经创建了WebApplicationContext实例,而在这个方法中最重要的就是对这个实例进行进一步的补充初始化。
父类FrameworkSerlvet覆盖了HttpServletBean中的initServletBean函数。
@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 { this.webApplicationContext = initWebApplicationContext(); //设计子类覆盖 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"); } }
initWebApplicationContext方法的主要工作就是创建或者刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化。
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } //刷新上下文环境 configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id //根据contextAttribute属性加载WebApplicationContext wac = findWebApplicationContext(); } if (wac == null) { // 通过以上2种方式没有找到,只能这里重新创建新的实例 wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. onRefresh(wac); } if (this.publishContext) { // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName(); 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 createWebApplicationContext(ApplicationContext parent) {//获取servlet的初始化参数Contextclass,如果没有配置 默认为XmlWebApplicationContext 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 + "]"); } 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"); }//通过反射方式实例化contextClass ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); //parent为在ContextLoaderListener中创建的WebApplicationContext实例 wac.setParent(parent); wac.setConfigLocation(getContextConfigLocation()); //初始化spring环境包括加载配置文件 configureAndRefreshWebApplicationContext(wac); return wac; }
configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName()); } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); } postProcessWebApplicationContext(wac); applyInitializers(wac); wac.refresh(); }
AbstractApplicationContext提供的refresh方法。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex); // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
继续看initWebApplicationContext方法调用DispatcherServlet类 onRefresh(wac)。
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } //一套完整的springmvc 配置属性 protected void initStrategies(ApplicationContext context) { //初始化MultipartResolver initMultipartResolver(context); //初始化LocaleResolver initLocaleResolver(context); //初始化ThemeResolver initThemeResolver(context); //初始化HandlerMappings :注册了 RequestMappingHandlerMapping和BeanNameUrlHandlerMapping initHandlerMappings(context); //初始化HandlerAdapters 注册了 RequestMappingHandlerAdapter、HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter initHandlerAdapters(context); //初始化HandlerExceptionResolvers initHandlerExceptionResolvers(context); //初始化RequestToViewNameTranslator initRequestToViewNameTranslator(context); //初始化ViewResolvers initViewResolvers(context); //初始化FlashMapManager initFlashMapManager(context); }
阅读全文
0 0
- springmvc 之DispatcherServlet初始化
- SpringMVC之DispatcherServlet初始化顺序。
- SpringMVC源码之解读DispatcherServlet初始化流程
- SpringMVC源码研究之DispatcherServlet初始化
- SpringMVC DispatcherServlet初始化过程
- SpringMVC DispatcherServlet 初始化过程
- 04.SpringMVC 初始化 - DispatcherServlet
- springMVC (四) DispatcherServlet 初始化
- SpringMVC之DispatcherServlet(1)Servlet的初始化
- springMvc DispatcherServlet的初始化过程
- SpringMvc之DispatcherServlet详解
- SpringMVC之DispatcherServlet
- SpringMVC之DispatcherServlet类
- SpringMVC之DispatcherServlet
- SpringMVC之DispatcherServlet配置。
- DispatcherServlet与初始化主线---SpringMVC(4)
- SpringMVC:dispatcherServlet对HandlerMapping的初始化
- SpringMVC深度探险-DispatcherServlet与初始化主线
- LeetCode87 Scramble String
- Android Studio 下对资源进行分包
- 简化版学生管理系统,主要思路
- 2017/10/15训练心得
- MySQL添加字段和删除字段
- springmvc 之DispatcherServlet初始化
- 什么防止你成为一个合格的程序员(痛痛痛点)
- 谈一谈Java中的Error和Exception
- 编程检验ASCLL码值与字符的关系
- 欢迎使用CSDN-markdown编辑器
- linux命令(data,tar)
- JUnit 单元测试报错 initializationerror [Runner:JUnit 4]
- 范式判定及修改
- IntelliJ IDEA mac下激活