博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC启动过程浅析
阅读量:4223 次
发布时间:2019-05-26

本文共 20049 字,大约阅读时间需要 66 分钟。

ContextLoaderListener初始化

ContextLoaderListener的作用就是启动web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener接口,当web容器启动时,会触发ServletContextListener的contextInitialized方法。

public interface ServletContextListener extends EventListener {
public void contextInitialized ( ServletContextEvent sce ); public void contextDestroyed ( ServletContextEvent sce );}

一般在web.xml中都会有如下配置,ContextLoaderListener是一个上下文载入器,同时它实现了ServletContextListener接口,也是一个最常用的Servlet监听器。

org.springframework.web.context.ContextLoaderListener

ServletContext启动之后会调用ServletContextListener的contextInitialized方法,我们进入到ContextLoaderListener的contextInitialized方法体。

public class ContextLoaderListener implements ServletContextListener {
private ContextLoader contextLoader; public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); this.contextLoader.initWebApplicationContext(event.getServletContext()); } protected ContextLoader createContextLoader() { return new ContextLoader(); } ……}public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } try { //载入根上下文的双亲上下文 ApplicationContext parent = loadParentContext(servletContext); this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context); …… return this.context; } …… }

上述代码首先判断在ServletContext中是否已经有根上下文存在了,如果存在,则抛出异常提示创建失败,如果不存在。

protected WebApplicationContext createWebApplicationContext(            ServletContext servletContext, ApplicationContext parent) throws BeansException {        Class contextClass = determineContextClass(servletContext);        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {            throw new ApplicationContextException("Custom context class [" + contextClass.getName() +                    "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");        }        ConfigurableWebApplicationContext wac =                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);        wac.setParent(parent);        wac.setServletContext(servletContext);        wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));        customizeContext(servletContext, wac);        wac.refresh();        return wac;    }    protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {        String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);        if (contextClassName != null) {            try {                return ClassUtils.forName(contextClassName);            }            catch (ClassNotFoundException ex) {                throw new ApplicationContextException(                        "Failed to load custom context class [" + contextClassName + "]", ex);            }        }        else {            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());            try {                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());            }            catch (ClassNotFoundException ex) {                throw new ApplicationContextException(                        "Failed to load default context class [" + contextClassName + "]", ex);            }        }    }    static {        try {            ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);        }        catch (IOException ex) {            throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());        }    }    private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";

根据上述静态代码块的内容,我们查看当前类ContextLoader同样目录下的ContextLoader.properties文件,内容如下:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

综上分析,在初始化的过程中,首先读取ContextLoader.properties内容,根据其中的配置提取将要实现WebApplicationContext接口的实现类,并根据这个实现类通过反射方式创建实例对象。

再回到ContextLoader的initWebApplicationContext方法中,createWebApplicationContext方法执行结束后,需要将实例对象记录到servletContext中,并映射当前的类加载器与创建的实例对象到全局变量currentContextPerThread中。

DispatcherServlet初始化

在完成对ContextLoaderListener的初始化之后,Web容器开始初始化DispatcherServlet。在Servlet的初始化阶段会调用其init方法,DispatcherServlet继承自FrameworkServlet,而FrameworkServlet继承自HttpServletBean,在HttpServletBean中找到了init方法。

public final void init() throws ServletException {        ……        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;            }        }        initServletBean();        if (logger.isDebugEnabled()) {            logger.debug("Servlet '" + getServletName() + "' configured successfully");        }    }

DispatcherServlet的初始化过程主要是先将web.xml中的init节点内容解析成Servlet类型实例,再将Servlet类型实例转换成BeanWrapper类型实例。最后进入initServletBean方法进行具体的初始化,FrameworkServlet扩展了此方法。

protected final void initServletBean() throws ServletException {        ……        try {            this.webApplicationContext = initWebApplicationContext();            initFrameworkServlet();        }        ……    }    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            wac = findWebApplicationContext();        }        if (wac == null) {            // No context instance is defined for this servlet -> create a local one            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 void onRefresh(ApplicationContext context) {        initStrategies(context);    }    protected void initStrategies(ApplicationContext context) {        initMultipartResolver(context);        initLocaleResolver(context);        initThemeResolver(context);        initHandlerMappings(context);        initHandlerAdapters(context);        initHandlerExceptionResolvers(context);        initRequestToViewNameTranslator(context);        initViewResolvers(context);        initFlashMapManager(context);    }

onRefresh是FrameworkServlet类中提供的模板方法,在其子类DispatcherServlet中进行了重写:

  • 初始化MultipartResolver
    在Spring中,MultipartResolver主要用于处理文件上传,默认情况下,Spring是没有MultipartResolver的,如果想使用,则需要在Web应用的上下文中添加MultipartResolver解析器。
private void initMultipartResolver(ApplicationContext context) {        try {            this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);            if (logger.isDebugEnabled()) {                logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");            }        }        catch (NoSuchBeanDefinitionException ex) {            // Default is no multipart resolver.            this.multipartResolver = null;            if (logger.isDebugEnabled()) {                logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +                        "': no multipart request handling provided");            }        }    }
  • 初始化LocaleResolver
    在Spring的国际化配置中一种有3中使用方式:基于URL参数的配置、基于session的配置、基于cookie的国际化配置。
private void initLocaleResolver(ApplicationContext context) {        try {            this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);            if (logger.isDebugEnabled()) {                logger.debug("Using LocaleResolver [" + this.localeResolver + "]");            }        }        catch (NoSuchBeanDefinitionException ex) {            // We need to use the default.            this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);            if (logger.isDebugEnabled()) {                logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +                        "': using default [" + this.localeResolver + "]");            }        }    }
  • 初始化ThemeResolver
private void initThemeResolver(ApplicationContext context) {        try {            this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);            if (logger.isDebugEnabled()) {                logger.debug("Using ThemeResolver [" + this.themeResolver + "]");            }        }        catch (NoSuchBeanDefinitionException ex) {            // We need to use the default.            this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);            if (logger.isDebugEnabled()) {                logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +                        "': using default [" + this.themeResolver + "]");            }        }    }
  • 初始化HandlerMapping
private void initHandlerMappings(ApplicationContext context) {        this.handlerMappings = null;        if (this.detectAllHandlerMappings) {            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.            Map
matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }
  • 初始化HandlerAdapter
private void initHandlerAdapters(ApplicationContext context) {        this.handlerAdapters = null;        if (this.detectAllHandlerAdapters) {            // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.            Map
matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList<>(matchingBeans.values()); // We keep HandlerAdapters in sorted order. AnnotationAwareOrderComparator.sort(this.handlerAdapters); } } else { try { HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class); this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerAdapter later. } } // Ensure we have at least some HandlerAdapters, by registering // default HandlerAdapters if no other adapters are found. if (this.handlerAdapters == null) { this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default"); } } }
  • 初始化HandlerExceptionResolver
private void initHandlerExceptionResolvers(ApplicationContext context) {        this.handlerExceptionResolvers = null;        if (this.detectAllHandlerExceptionResolvers) {            // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.            Map
matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values()); // We keep HandlerExceptionResolvers in sorted order. AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers); } } else { try { HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); this.handlerExceptionResolvers = Collections.singletonList(her); } catch (NoSuchBeanDefinitionException ex) { // Ignore, no HandlerExceptionResolver is fine too. } } // Ensure we have at least some HandlerExceptionResolvers, by registering // default HandlerExceptionResolvers if no other resolvers are found. if (this.handlerExceptionResolvers == null) { this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default"); } } }
  • 初始化RequestToViewNameTranslator
private void initRequestToViewNameTranslator(ApplicationContext context) {        try {            this.viewNameTranslator =                    context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);            if (logger.isDebugEnabled()) {                logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");            }        }        catch (NoSuchBeanDefinitionException ex) {            // We need to use the default.            this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);            if (logger.isDebugEnabled()) {                logger.debug("Unable to locate RequestToViewNameTranslator with name '" +                        REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +                        "]");            }        }    }
  • 初始化ViewResolvers
private void initViewResolvers(ApplicationContext context) {        this.viewResolvers = null;        if (this.detectAllViewResolvers) {            // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.            Map
matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.viewResolvers = new ArrayList<>(matchingBeans.values()); // We keep ViewResolvers in sorted order. AnnotationAwareOrderComparator.sort(this.viewResolvers); } } else { try { ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class); this.viewResolvers = Collections.singletonList(vr); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default ViewResolver later. } } // Ensure we have at least one ViewResolver, by registering // a default ViewResolver if no other resolvers are found. if (this.viewResolvers == null) { this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); if (logger.isDebugEnabled()) { logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default"); } } }
  • 初始化FlashMapManager
private void initFlashMapManager(ApplicationContext context) {        try {            this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);            if (logger.isDebugEnabled()) {                logger.debug("Using FlashMapManager [" + this.flashMapManager + "]");            }        }        catch (NoSuchBeanDefinitionException ex) {            // We need to use the default.            this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);            if (logger.isDebugEnabled()) {                logger.debug("Unable to locate FlashMapManager with name '" +                        FLASH_MAP_MANAGER_BEAN_NAME + "': using default [" + this.flashMapManager + "]");            }        }    }

转载地址:http://jpgmi.baihongyu.com/

你可能感兴趣的文章
主键和唯一索引的区别
查看>>
linux下使用yum安装gcc详解
查看>>
aclocal安装依赖的库
查看>>
FastDFS 安装及使用详解
查看>>
ERROR 1045 (28000): Access denied for user root@localhost (using password: NO)解决方案
查看>>
Host 'XXX' is not allowed to connect to this MySQL server解决方案
查看>>
corosync pacemaker 配置高可用集群(一)
查看>>
5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
查看>>
nginx(一) nginx详解
查看>>
nginx(二) nginx编译安装 及 配置WEB服务
查看>>
nginx(三) nginx配置:反向代理 负载均衡 后端健康检查 缓存
查看>>
nginx(四) nginx+keepalived 实现主备+双主热备模型的高可用负载均衡代理服务
查看>>
jQuery核心--多库共存
查看>>
4 51 单片机最小系统
查看>>
6 51点亮第一个LED
查看>>
8 51 LED流水灯
查看>>
Multisim 14.0 搭建并仿真51单片机最小系统
查看>>
51 中断系统 外部中断0 外部中断1
查看>>
51 单片机 时间/计数器中断
查看>>
腾讯云本地还原mysql物理冷备
查看>>