• Spring MVC(一)Servlet 2.x 规范在 Spring MVC 中的应用


    Spring MVC(一)Servlet 2.x 规范在 Spring MVC 中的应用

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

    《Servlet 2.x 规范》:https://www.cnblogs.com/binarylei/p/10205884.html

    Servlet 容器在启动时会调用 ServletContextListener 的 contextInitialized() 方法。同时 Servlet 在初始化时会执行 init 方法。Spring MVC 正是在这两个过程中创建 Root WebApplicationContext 和 Servlet WebApplicationContext 容器。

    WebApplicationContext

    一、ContextLoaderListener

    ContextLoaderListener

    ContextLoaderListener 的 contextInitialized 只是简单的调用了一个其父类 ContextLoader 的 initWebApplicationContext 方法,创建了一个 Root 容器。

    // 创建 Root WebApplicationContext
    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        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");
        }
        try {
            // 1. 创建 Root WebApplicationContext
            if (this.context == null) {
                this.context = createWebApplicationContext(servletContext);
            }
            // 2. 配置 Root WebApplicationContext
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
            
            // 3. 保存 context
            ClassLoader ccl = Thread.currentThread().getContextClassLoader();
            if (ccl == ContextLoader.class.getClassLoader()) {
                currentContext = this.context;
            } else if (ccl != null) {
                currentContextPerThread.put(ccl, this.context);
            }
            return this.context;
        } catch (RuntimeException | Error ex) {
        }
    }
    

    二、DispatcherServlet

    类继承关系:DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> Servlet
    

    初始化 DispatcherServlet 时会调用 Servlet 的 init() 方法。

    // HttpServletBean#init
    @Override
    public final void init() throws ServletException {
        // 省略...
        initServletBean();
    }
    
    // FrameworkServlet#initServletBean
    @Override
    protected final void initServletBean() throws ServletException {
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }
    

    至此终于看到 Servlet WebApplicationContext 的创建了。

    protected WebApplicationContext initWebApplicationContext() {
        // 1. 获取父容器
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
    
        // 2. 子容器已经存在则设置其父容器并启动
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
    
        // 3. 不存在则创建一个新子容器
        if (wac == null) {
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            wac = createWebApplicationContext(rootContext);
        }
    
        if (!this.refreshEventReceived) {
            onRefresh(wac);
        }
        if (this.publishContext) {
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }
    

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    Debug小技巧,抓线程的栈信息
    NPOI EXECL数据导入,日期格式调用DateCellValue取值时,二次或后续调用出现报错!
    vs2019 entityframe(EF) 连接Oracle 提示 但未在用户代码中进行处理 具有固定名称“Oracle.ManagedDataAccess.Client”的 ADO.NET 提供程序未在计算机或应用程序配置文件中注册或无法加载。
    idea使用技巧
    projectEuler 12 Highly divisible triangular number
    hdu7024 Penguin Love Tour(2021杭电暑假多校5)树形dp
    hdu7020 Array(2021杭电暑假多校5)多数投票算法
    nowcoder11254A Guess and lies(2021牛客暑期多校训练营3)dp
    hdu6970 I love permutation(2021杭电暑假多校2) 数学
    nowcoder11166H Hash Function(2021牛客暑期多校训练营1) fft
  • 原文地址:https://www.cnblogs.com/binarylei/p/10206138.html
Copyright © 2020-2023  润新知