• Spring web 工具类 WebApplicationContextUtils


    概述

    Spring web 的工具类 WebApplicationContextUtils 位于包

    org.springframework.web.context.support

    是访问一个ServletContext的根WebApplicationContext的便捷方法类。该工具类提供了如下工具方法 :

    1. 在web容器启动过程中注册web相关作用域bean : request,session , globalSession , application

    2. 在web容器启动过程中注册相应类型的工厂bean,开发人员依赖注入相应的bean时能访问到正确的请求/响应/会话
      对象 : ServletRequest,ServletResponse,HttpSession,WebRequest

    3. 在web容器启动过程中注册web相关环境bean : contextParameters , contextAttributes

    4. 在web容器启动过程中初始化servlet propertySources

    5. 在客户化web视图(custom web view)或者MVC action中,使用该工具类可以很方便地在程序中访问Spring应用上下文(application context)。

    源代码解析

    /*
     * Copyright 2002-2016 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.web.context.support;
    
    import java.io.Serializable;
    import java.util.Collections;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Map;
    import javax.faces.context.ExternalContext;
    import javax.faces.context.FacesContext;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpSession;
    
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.core.env.MutablePropertySources;
    import org.springframework.core.env.PropertySource.StubPropertySource;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    import org.springframework.web.context.ConfigurableWebApplicationContext;
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.RequestScope;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.context.request.ServletWebRequest;
    import org.springframework.web.context.request.SessionScope;
    import org.springframework.web.context.request.WebRequest;
    
    /**
     * Convenience methods for retrieving the root WebApplicationContext for
     * a given ServletContext. This is useful for programmatically accessing
     * a Spring application context from within custom web views or MVC actions.
     *
     * Note that there are more convenient ways of accessing the root context for
     * many web frameworks, either part of Spring or available as an external library.
     * This helper class is just the most generic way to access the root context.
     *
     * @author Juergen Hoeller
     * @see org.springframework.web.context.ContextLoader
     * @see org.springframework.web.servlet.FrameworkServlet
     * @see org.springframework.web.servlet.DispatcherServlet
     * @see org.springframework.web.jsf.FacesContextUtils
     * @see org.springframework.web.jsf.el.SpringBeanFacesELResolver
     */
    public abstract class WebApplicationContextUtils {
    
        private static final boolean jsfPresent =
                ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
    
    
        /**
         * Find the root WebApplicationContext for this web app, typically
         * loaded via org.springframework.web.context.ContextLoaderListener.
         * 
         * 根据参数sc指定的ServletContext,找到当前web应用的根WebApplicationContext,该根WebApplicationContext
         * 典型情况下由加载org.springframework.web.context.ContextLoaderListener,
         * 并记录为ServletContext的属性,属性名称使用
         * WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 
         * 
         * Will rethrow an exception that happened on root context startup,
         * to differentiate between a failed context startup and no context at all.
         *  
         * 如果根上下文(root context)启动过程中有异常发生,这里会把该异常重新抛出;如果根本找不到根上下文,
         * 抛出另外一个异常IllegalStateException,带如下错误信息 : 
         * No WebApplicationContext found: no ContextLoaderListener registered?
         * 
         * @param sc ServletContext to find the web application context for
         * @return the root WebApplicationContext for this web app
         * @throws IllegalStateException if the root WebApplicationContext could not be found
         * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
         */
        public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc) throws IllegalStateException {
            WebApplicationContext wac = getWebApplicationContext(sc);
            if (wac == null) {
                throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
            }
            return wac;
        }
    
        /**
         * Find the root WebApplicationContext for this web app, typically
         * loaded via org.springframework.web.context.ContextLoaderListener.
         * 
         * 根据参数sc指定的ServletContext,找到当前web应用的根WebApplicationContext,该根WebApplicationContext
         * 典型情况下由加载org.springframework.web.context.ContextLoaderListener,
         * 并记录为ServletContext的属性,属性名称使用
         * WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
         *   
         * Will rethrow an exception that happened on root context startup,
         * to differentiate between a failed context startup and no context at all.
         * 
         * 如果根上下文(root context)启动过程中有异常发生,这里会把该异常重新抛出;如果根本找不到根上下文,
         * 返回null,注意,这一点是该方法和方法getRequiredWebApplicationContext不同的地方
    
         * @param sc ServletContext to find the web application context for
         * @return the root WebApplicationContext for this web app, or null if none
         * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
         */
        public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
            return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        }
    
        /**
         * Find a custom WebApplicationContext for this web app.
         * 
         * 根据指定的名称找到ServletContext的某个WebApplicationContext,
         * 这些WebApplicationContext会在容器启动过程中添加为ServletContext实例特定名字的属性对象,
         * 如果这些WebApplicationContext在容器准备他们的过程中遇到了异常,相应的属性对象记录的是相应的异常
         * @param sc ServletContext to find the web application context for
         * @param attrName the name of the ServletContext attribute to look for
         * @return the desired WebApplicationContext for this web app, or null if none
         */
        public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
            Assert.notNull(sc, "ServletContext must not be null");
            Object attr = sc.getAttribute(attrName);
            if (attr == null) {
            //如果该属性不存在,返回null
                return null;
            }
            if (attr instanceof RuntimeException) {
            // 如果该属性对象是运行时异常,抛出该异常,这种情况说明容器在启动过程中准备该WebApplicationContext
            // 遇到了异常
                throw (RuntimeException) attr;
            }
            if (attr instanceof Error) {
            // 如果该属性对象是错误,抛出该错误,这种情况说明容器在启动过程中准备该WebApplicationContext
            // 遇到了异常        
                throw (Error) attr;
            }
            if (attr instanceof Exception) {
            // 如果该属性对象是一般异常,抛出该异常,这种情况说明容器在启动过程中准备该WebApplicationContext
            // 遇到了异常        
                throw new IllegalStateException((Exception) attr);
            }
            if (!(attr instanceof WebApplicationContext)) {
            // 如果该属性对象不是异常,不是错误,也不是WebApplicationContext,抛出一个异常表明该问题
                throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
            }
            return (WebApplicationContext) attr;
        }
    
        /**
         * Find a unique WebApplicationContext for this web app: either the
         * root web app context (preferred) or a unique WebApplicationContext
         * among the registered ServletContext attributes (typically coming
         * from a single DispatcherServlet in the current web application).
         * 
         * 找到当前Web应用唯一的那个WebApplicationContext:或者是缺省根web应用上下文(期望的情况),
         * 或者是注册的ServletContext属性中唯一的那个WebApplicationContext(典型情况下,来自当前
         * web应用中的DispatcherServlet)。如果发现注册的ServletContext属性中有多个WebApplicationContext,
         * 会抛出异常声明发现了多个WebApplicationContext。
         * 
         * Note that DispatcherServlet's exposure of its context can be
         * controlled through its publishContext property, which is true
         * by default but can be selectively switched to only publish a single context
         * despite multiple DispatcherServlet registrations in the web app.
         * @param sc ServletContext to find the web application context for
         * @return the desired WebApplicationContext for this web app, or null if none
         * @since 4.2
         * @see #getWebApplicationContext(ServletContext)
         * @see ServletContext#getAttributeNames()
         */
        public static WebApplicationContext findWebApplicationContext(ServletContext sc) {
            // 尝试获取根web应用上下文,如果找得到则返回根web应用上下文
            WebApplicationContext wac = getWebApplicationContext(sc);
            if (wac == null) {
            // 如果没有找到根web应用上下文,尝试从ServletContext的属性中查找唯一的一个WebApplicationContext
            // 并返回,如果找到的WebApplicationContext不唯一,则抛出异常声明该情况
                Enumeration<String> attrNames = sc.getAttributeNames();
                while (attrNames.hasMoreElements()) {
                    String attrName = attrNames.nextElement();
                    Object attrValue = sc.getAttribute(attrName);
                    if (attrValue instanceof WebApplicationContext) {
                        if (wac != null) {
                            throw new IllegalStateException("No unique WebApplicationContext found: more than one " +
                                    "DispatcherServlet registered with publishContext=true?");
                        }
                        wac = (WebApplicationContext) attrValue;
                    }
                }
            }
            return wac;
        }
    
    
        /**
         * Register web-specific scopes ("request", "session", "globalSession")
         * with the given BeanFactory, as used by the WebApplicationContext.
         * @param beanFactory the BeanFactory to configure
         */
        public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
            registerWebApplicationScopes(beanFactory, null);
        }
    
        /**
         * Register web-specific scopes ("request", "session", "globalSession", "application")
         * with the given BeanFactory, as used by the WebApplicationContext.
         *  
         * 向WebApplicationContext使用的BeanFactory注册web有关作用域对象 :
         * request, session, globalSession, application
         * @param beanFactory the BeanFactory to configure
         * @param sc the ServletContext that we're running within
         */
        public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
            // 注册web相关作用域bean
            beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
            beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
            beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
            if (sc != null) {
                ServletContextScope appScope = new ServletContextScope(sc);
                beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
                // Register as ServletContext attribute, for ContextCleanupListener to detect it.
                sc.setAttribute(ServletContextScope.class.getName(), appScope);
            }
    
            // 注册ServletRequest的工厂bean,当开发人员依赖注入ServletRequest对象时,注入的bean其实是这里的
            // RequestObjectFactory工厂bean
            beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    
            // 注册ServletResponse的工厂bean,当开发人员依赖注入ServletResponse对象时,注入的bean其实是这里的
            // ResponseObjectFactory工厂bean      
            beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
    
            // 注册HttpSession的工厂bean,当开发人员依赖注入HttpSession对象时,注入的bean其实是这里的
            // SessionObjectFactory工厂bean               
            beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    
            // 注册WebRequest的工厂bean,当开发人员依赖注入WebRequest对象时,注入的bean其实是这里的
            // WebRequestObjectFactory工厂bean            
            beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
    
            if (jsfPresent) {
                FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
            }
        }
    
        /**
         * Register web-specific environment beans ("contextParameters", "contextAttributes")
         * with the given BeanFactory, as used by the WebApplicationContext.
         * @param bf the BeanFactory to configure
         * @param sc the ServletContext that we're running within
         */
        public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, ServletContext sc) {
            registerEnvironmentBeans(bf, sc, null);
        }
    
        /**
         * Register web-specific environment beans ("contextParameters", "contextAttributes")
         * with the given BeanFactory, as used by the WebApplicationContext.
         * @param bf the BeanFactory to configure
         * @param servletContext the ServletContext that we're running within
         * @param servletConfig the ServletConfig of the containing Portlet
         */
        public static void registerEnvironmentBeans(
                ConfigurableListableBeanFactory bf, ServletContext servletContext, ServletConfig servletConfig) {
    
            if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) {
                bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
            }
    
            if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {
                bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig);
            }
    
            if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) {
                Map<String, String> parameterMap = new HashMap<String, String>();
                if (servletContext != null) {
                    Enumeration<?> paramNameEnum = servletContext.getInitParameterNames();
                    while (paramNameEnum.hasMoreElements()) {
                        String paramName = (String) paramNameEnum.nextElement();
                        parameterMap.put(paramName, servletContext.getInitParameter(paramName));
                    }
                }
                if (servletConfig != null) {
                    Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames();
                    while (paramNameEnum.hasMoreElements()) {
                        String paramName = (String) paramNameEnum.nextElement();
                        parameterMap.put(paramName, servletConfig.getInitParameter(paramName));
                    }
                }
                bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME,
                        Collections.unmodifiableMap(parameterMap));
            }
    
            if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) {
                Map<String, Object> attributeMap = new HashMap<String, Object>();
                if (servletContext != null) {
                    Enumeration<?> attrNameEnum = servletContext.getAttributeNames();
                    while (attrNameEnum.hasMoreElements()) {
                        String attrName = (String) attrNameEnum.nextElement();
                        attributeMap.put(attrName, servletContext.getAttribute(attrName));
                    }
                }
                bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME,
                        Collections.unmodifiableMap(attributeMap));
            }
        }
    
        /**
         * Convenient variant of #initServletPropertySources(MutablePropertySources,
         * ServletContext, ServletConfig) that always provides null for the
         * ServletConfig parameter.
         * @see #initServletPropertySources(MutablePropertySources, ServletContext, ServletConfig)
         */
        public static void initServletPropertySources(MutablePropertySources propertySources, ServletContext servletContext) {
            initServletPropertySources(propertySources, servletContext, null);
        }
    
        /**
         * Replace Servlet-based StubPropertySource stub property sources with
         * actual instances populated with the given servletContext and
         * servletConfig objects.
         * This method is idempotent with respect to the fact it may be called any number
         * of times but will perform replacement of stub property sources with their
         * corresponding actual property sources once and only once.
         * @param propertySources the MutablePropertySources to initialize (must not
         * be null)
         * @param servletContext the current ServletContext (ignored if null
         * or if the StandardServletEnvironment#SERVLET_CONTEXT_PROPERTY_SOURCE_NAME
         * servlet context property source has already been initialized)
         * @param servletConfig the current ServletConfig (ignored if null
         * or if the StandardServletEnvironment#SERVLET_CONFIG_PROPERTY_SOURCE_NAME
         * servlet config property source} has already been initialized)
         * @see org.springframework.core.env.PropertySource.StubPropertySource
         * @see org.springframework.core.env.ConfigurableEnvironment#getPropertySources()
         */
        public static void initServletPropertySources(
                MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {
    
            Assert.notNull(propertySources, "'propertySources' must not be null");
            if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
                    propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
                propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
                        new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
            }
            if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
                    propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
                propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
                        new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
            }
        }
    
        /**
         * Return the current RequestAttributes instance as ServletRequestAttributes.
         * 
         * 获取当前RequestAttributes实例,返回类型为ServletRequestAttributes,
         * 该方法使用RequestContextHolder获取和当前请求处理线程绑定的ServletRequestAttributes对象,
         * 进而可以获取其中的HttpServletRequest/HttpServletResponse对象
         * 
         * 该类定义该方法的目的是给该类的以下四个私有嵌套静态类使用 : 
         * RequestObjectFactory,ResponseObjectFactory,SessionObjectFactory,WebRequestObjectFactory
         * @see RequestContextHolder#currentRequestAttributes()
         */
        private static ServletRequestAttributes currentRequestAttributes() {
            RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
            if (!(requestAttr instanceof ServletRequestAttributes)) {
                throw new IllegalStateException("Current request is not a servlet request");
            }
            return (ServletRequestAttributes) requestAttr;
        }
    
    // 在下面的代码中,该类定义了四个私有嵌套静态类 : 
    // RequestObjectFactory,ResponseObjectFactory,SessionObjectFactory,WebRequestObjectFactory
    // 这四个静态类是四个工厂类,分别用于生成ServletRequest,ServletResponse,HttpSession,WebRequest对象,
    // 当开发人员使用@Autowired分别注入了以上四种类型的bean时,返回的其实是下面四个工厂类的对象,这四个工厂类对象
    // 均使用了上面定义的currentRequestAttributes()方法,能从当前请求处理线程中获取正确的ServletRequestAttributes
    // 对象,进而获取正确的ServletRequest,ServletResponse,HttpSession,WebRequest对象
    
        /**
         * Factory that exposes the current request object on demand.
         */
        @SuppressWarnings("serial")
        private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
    
            @Override
            public ServletRequest getObject() {
                return currentRequestAttributes().getRequest();
            }
    
            @Override
            public String toString() {
                return "Current HttpServletRequest";
            }
        }
    
    
        /**
         * Factory that exposes the current response object on demand.
         */
        @SuppressWarnings("serial")
        private static class ResponseObjectFactory implements ObjectFactory<ServletResponse>, Serializable {
    
            @Override
            public ServletResponse getObject() {
                ServletResponse response = currentRequestAttributes().getResponse();
                if (response == null) {
                    throw new IllegalStateException("Current servlet response not available - " +
                            "consider using RequestContextFilter instead of RequestContextListener");
                }
                return response;
            }
    
            @Override
            public String toString() {
                return "Current HttpServletResponse";
            }
        }
    
    
        /**
         * Factory that exposes the current session object on demand.
         */
        @SuppressWarnings("serial")
        private static class SessionObjectFactory implements ObjectFactory<HttpSession>, Serializable {
    
            @Override
            public HttpSession getObject() {
                return currentRequestAttributes().getRequest().getSession();
            }
    
            @Override
            public String toString() {
                return "Current HttpSession";
            }
        }
    
    
        /**
         * Factory that exposes the current WebRequest object on demand.
         */
        @SuppressWarnings("serial")
        private static class WebRequestObjectFactory implements ObjectFactory<WebRequest>, Serializable {
    
            @Override
            public WebRequest getObject() {
                ServletRequestAttributes requestAttr = currentRequestAttributes();
                return new ServletWebRequest(requestAttr.getRequest(), requestAttr.getResponse());
            }
    
            @Override
            public String toString() {
                return "Current ServletWebRequest";
            }
        }
    
    
        /**
         * Inner class to avoid hard-coded JSF dependency.
         */
        private static class FacesDependencyRegistrar {
    
            public static void registerFacesDependencies(ConfigurableListableBeanFactory beanFactory) {
                beanFactory.registerResolvableDependency(FacesContext.class, new ObjectFactory<FacesContext>() {
                    @Override
                    public FacesContext getObject() {
                        return FacesContext.getCurrentInstance();
                    }
                    @Override
                    public String toString() {
                        return "Current JSF FacesContext";
                    }
                });
                beanFactory.registerResolvableDependency(ExternalContext.class, new ObjectFactory<ExternalContext>() {
                    @Override
                    public ExternalContext getObject() {
                        return FacesContext.getCurrentInstance().getExternalContext();
                    }
                    @Override
                    public String toString() {
                        return "Current JSF ExternalContext";
                    }
                });
            }
        }
    
    }
    
  • 相关阅读:
    'abbdsjjtb',找出该字符串中最后一个只出现一次的字符,并且得到这个字符的位置
    2.jira的测试人员使用流程
    jmeter41: singn接口md5签名接口
    jmeter40:RandomDate+Random实现随机日期+随机时间
    5排序函数,sort一般只能对列表进行排序,sorted函数可以对列表或者字典排序
    u盘重装系统时提示“我们找不到任何驱动器,要获取存储设备驱动程序”解决方案
    TCL数组——array
    TCL 笔记
    Ubuntu使用一周感想
    ④ vue 中的动画
  • 原文地址:https://www.cnblogs.com/jpfss/p/9447915.html
Copyright © 2020-2023  润新知