Spring 源码解析之DispatcherServlet源码解析(五)

Spring 源码解析之DispatcherServlet源码解析(五)

前言

本文需要有前四篇文章的基础,才能够清晰易懂,有兴趣可以先看看详细的流程,这篇文章可以说是第一篇文章,也可以说是前四篇文章的的汇总,Spring的整个请求流程都是围绕着DispatcherServlet进行的

类结构图

根据类的结构来说DispatcherServlet本身也是继承了HttpServlet的,所有的请求都是根据这一个Servlet来进行转发的,同时解释了为什么需要在web.xml进行如下配置,因为Spring是基于一个Servlet来展开的,当然不需要Servlet也能够使用Spring

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>  

1 DispatcherServlet初始化

1.1 DispatcherServlet初始化加载的几个bean

protected void initStrategies(ApplicationContext context) {
    //初始化文件上传处理类
        initMultipartResolver(context);
    //初始化本地化Resolver
        initLocaleResolver(context);
    //初始化主题Resolver
        initThemeResolver(context);
    //初始化一些个与处理的HandlerMappings
        initHandlerMappings(context);
    //
        initHandlerAdapters(context);
    //初始化异常处理的handler
        initHandlerExceptionResolvers(context);
    //初始化请求路径转换为ViewName 的Translator
        initRequestToViewNameTranslator(context);
  //初始化ViewResolvers 这个就是针对视图处理的Resolvers 比如jsp处理Resolvers 或者freemarker处理Resolvers
        initViewResolvers(context);
    //初始化 主要管理flashmap,比如RedirectAttributes 的属性会放到这个里面,默认使用的是SessionFlashMapManager
        initFlashMapManager(context);
    }

1.2 初始化流程图

1.2.1 HttpServletBean源码解析

HttpServletBean本身来说是一个普通的servlet而已,主要做一些资源的初始化

public abstract class HttpServletBean extends HttpServlet
        implements EnvironmentCapable, EnvironmentAware {

    protected final Log logger = LogFactory.getLog(getClass());

    /**
     * Set of required properties (Strings) that must be supplied as
     * config parameters to this servlet.
     */
    private final Set<String> requiredProperties = new HashSet<String>();

    private ConfigurableEnvironment environment;

    /**
     * Subclasses can invoke this method to specify that this property
     * (which must match a JavaBean property they expose) is mandatory,
     * and must be supplied as a config parameter. This should be called
     * from the constructor of a subclass.
     * <p>This method is only relevant in case of traditional initialization
     * driven by a ServletConfig instance.
     * @param property name of the required property
     */
    protected final void addRequiredProperty(String property) {
        this.requiredProperties.add(property);
    }

    /**
     * Map config parameters onto bean properties of this servlet, and
     * invoke subclass initialization.
     * @throws ServletException if bean properties are invalid (or required
     * properties are missing), or if subclass initialization fails.
     */
    @Override
    public final void init() throws ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing servlet ‘" + getServletName() + "‘");
        }

        // Set bean properties from init parameters.
        try {
      //使用Servlet配置的初始化参数创建一个PropertyValues对象,PropertyValues对象是名值对的集合, 子类也可以指定哪些属性是必须的
            PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
      //把当前的Servlet当作一个Bean, 把Bean的属性以及属性的存取方法信息放入BeanWrapper对象
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
      //注册一个可以在资源和路径之间进行转化的客户化编辑器,这些资源是这个Web应用的内部资源,例如,一个文件,一个图片等等
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
       //提供给子类机会增加更多的客户化的编辑器,或者对BeanWrapper进行更多的初始化
            initBeanWrapper(bw);
      //把初始化制定的参数值赋值到Servlet的属性中,第二个参数true表明忽略位置属性
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            logger.error("Failed to set bean properties on servlet ‘" + getServletName() + "‘", ex);
            throw ex;
        }

        // Let subclasses do whatever initialization they like.
    //提供给子类的的初始化方法 目前是FrameworkServlet 进行了实现
        initServletBean();

        if (logger.isDebugEnabled()) {
            logger.debug("Servlet ‘" + getServletName() + "‘ configured successfully");
        }
    }

    /**
     * Initialize the BeanWrapper for this HttpServletBean,
     * possibly with custom editors.
     * <p>This default implementation is empty.
     * @param bw the BeanWrapper to initialize
     * @throws BeansException if thrown by BeanWrapper methods
     * @see org.springframework.beans.BeanWrapper#registerCustomEditor
     */
    protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
    }

    /**
     * Overridden method that simply returns {@code null} when no
     * ServletConfig set yet.
     * @see #getServletConfig()
     */
    @Override
    public final String getServletName() {
        return (getServletConfig() != null ? getServletConfig().getServletName() : null);
    }

    /**
     * Overridden method that simply returns {@code null} when no
     * ServletConfig set yet.
     * @see #getServletConfig()
     */
    @Override
    public final ServletContext getServletContext() {
        return (getServletConfig() != null ? getServletConfig().getServletContext() : null);
    }

    /**
     * Subclasses may override this to perform custom initialization.
     * All bean properties of this servlet will have been set before this
     * method is invoked.
     * <p>This default implementation is empty.
     * @throws ServletException if subclass initialization fails
     */
    protected void initServletBean() throws ServletException {
    }

    /**
     * {@inheritDoc}
     * @throws IllegalArgumentException if environment is not assignable to
     * {@code ConfigurableEnvironment}.
     */
    @Override
    public void setEnvironment(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        this.environment = (ConfigurableEnvironment) environment;
    }

    /**
     * {@inheritDoc}
     * <p>If {@code null}, a new environment will be initialized via
     * {@link #createEnvironment()}.
     */
    @Override
    public ConfigurableEnvironment getEnvironment() {
        if (this.environment == null) {
            this.environment = this.createEnvironment();
        }
        return this.environment;
    }

    /**
     * Create and return a new {@link StandardServletEnvironment}. Subclasses may override
     * in order to configure the environment or specialize the environment type returned.
     */
    protected ConfigurableEnvironment createEnvironment() {
        return new StandardServletEnvironment();
    }

    /**
     * PropertyValues implementation created from ServletConfig init parameters.
     */
   //主要是用来添加初始化参数的
    private static class ServletConfigPropertyValues extends MutablePropertyValues {

        /**
         * Create new ServletConfigPropertyValues.
         * @param config ServletConfig we‘ll use to take PropertyValues from
         * @param requiredProperties set of property names we need, where
         * we can‘t accept default values requiredProperties 这个参数主要是指定初始化时必须添加的参数
         * @throws ServletException if any required properties are missing
         */
        public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
            throws ServletException {

            Set<String> missingProps = (requiredProperties != null && !requiredProperties.isEmpty()) ?
                    new HashSet<String>(requiredProperties) : null;

            Enumeration<String> en = config.getInitParameterNames();
            while (en.hasMoreElements()) {
                String property = en.nextElement();
                Object value = config.getInitParameter(property);
                addPropertyValue(new PropertyValue(property, value));
                if (missingProps != null) {
                    missingProps.remove(property);
                }
            }

            // Fail if we are still missing properties.
            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, ", "));
            }
        }
    }

}

1.2.1 FrameworkServlet源码解析

这里只贴初始化的需要的部分代码,根据上面的逻辑,子类实现了initServletBean()这个方法进行初始化

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

    protected void initFrameworkServlet() throws ServletException {
    }
    //实现HttpServletBean 的初始化接口
    @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();
        //这个是留给子类去实现的方法,暂时来说没有具体的实现,主要是留给开发人员自定义一些特性的时候
        //这个时候WebApplicationContext已经被初始化了,也就是一些个spring的配置文件已经被初始化了
            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");
        }
    }

    protected WebApplicationContext initWebApplicationContext() {
    //获取根的Context对象,比如说我用了Spring boot或者注解的方式进行初始化,那么这里的Context就是Spring boot或者其他的context对象
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
    //如果当前的webApplicationContext 不等于null
        if (this.webApplicationContext != null) {
            // A context instance was injected at construction time -> use it
            wac = this.webApplicationContext;
      //如果context对象是ConfigurableWebApplicationContext
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
        //如果ConfigurableWebApplicationContext 不是存活状态
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
          //如果没有设置过parent
                    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
      //查询当前的Context,下述有详细讲解
            wac = findWebApplicationContext();
        }
    //如果没有找到那么就通过rootContext 去创建一个Context对象
        if (wac == null) {
            // No context instance is defined for this servlet -> create a local one
            wac = createWebApplicationContext(rootContext);
        }
    //如果允许通过事件通知,那么就直接初始化。通过事件的通知可以反向的说明onRefresh()这个方法是可以被重复调用的,具体分析看下面
        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);
        }
    // Publish the context as a servlet context attribute.
  //如果允许publish Context的话那么就把spring context放入到spring的ServletContext中
        if (this.publishContext) {
            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;
    }
  //创建and refresh WebApplicationContext
  protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    //判断id
        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());
    //添加针对ContextRefreshListener事件的监听
    //ApplicationListener decorator that filters events from a specified event source, invoking its delegate listener for matching ApplicationEvent objects only.
    //看了一下英文,大概是用了decorator(装饰)模式,具体源码里面,也只是做了一个简单的装饰模式,这个类接受所有的ApplicationEvent事件
        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());
        }
    //Post-process the given WebApplicationContext before it is refreshed
    //大概就是说,在初始化handlermapping和一些本地化等调用refresh方法之前处理WebApplicationContext,这个类没有具体实现,开发者可以自己去处理
        postProcessWebApplicationContext(wac);
    //spring dispatcherServlet初始化的时候可以指定初始化一些类
        applyInitializers(wac);
    //这个是重点方法,这里采用了事件的模式进行通知,去调用refresh方法初始化配置
        wac.refresh();
    }
  //初始化spring context的时候 初始化一些指定需要初始化的类 这些类需要实现ApplicationContextInitializer 这个接口才能进行调用
  protected void applyInitializers(ConfigurableApplicationContext wac) {
    //获取到ServletContext中初始化的类数组参数
    //
        String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
        if (globalClassNames != null) {
      //不断的去初始化这个类数组 以,;\t\n等作为分隔符
            for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
                this.contextInitializers.add(loadInitializer(className, wac));
            }
        }

        if (this.contextInitializerClasses != null) {
            for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {
                this.contextInitializers.add(loadInitializer(className, wac));
            }
        }
    //排序,可以指定这些类的初始化顺序,通过@Order注解来实现排序
        AnnotationAwareOrderComparator.sort(this.contextInitializers);
    //初始化
        for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
            initializer.initialize(wac);
        }
    }
  //初始化类,
  private ApplicationContextInitializer<ConfigurableApplicationContext> loadInitializer(
            String className, ConfigurableApplicationContext wac) {
        try {
      //加载这个类
            Class<?> initializerClass = ClassUtils.forName(className, wac.getClassLoader());
      //判断是否实现了接口ApplicationContextInitializer
            Class<?> initializerContextClass =
                    GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
            if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
                throw new ApplicationContextException(String.format(
                        "Could not apply context initializer [%s] since its generic parameter [%s] " +
                        "is not assignable from the type of application context used by this " +
                        "framework servlet: [%s]", initializerClass.getName(), initializerContextClass.getName(),
                        wac.getClass().getName()));
            }
      //初始化对象
            return BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class);
        }
        catch (ClassNotFoundException ex) {
            throw new ApplicationContextException(String.format("Could not load class [%s] specified " +
                    "via ‘contextInitializerClasses‘ init-param", className), ex);
        }
    }
}

上述代码获取root Context的时候可以通过如下代码了解到获取方式,webapp的Context对象的保存,其实无非就是把spring的context放到了ServletContext的一个属性中而已

WebApplicationContext rootContext =
    WebApplicationContextUtils.getWebApplicationContext(getServletContext());
public abstract class WebApplicationContextUtils {
  public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
        return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    }

    /**
     * Find a custom {@code WebApplicationContext} for this web app.
     * @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 {@code null} if none
     */
    public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
        Assert.notNull(sc, "ServletContext must not be null");
    //通过从ServletContext 去获取spring的context对象
        Object attr = sc.getAttribute(attrName);
        if (attr == null) {
            return null;
        }
        if (attr instanceof RuntimeException) {
            throw (RuntimeException) attr;
        }
        if (attr instanceof Error) {
            throw (Error) attr;
        }
        if (attr instanceof Exception) {
            throw new IllegalStateException((Exception) attr);
        }
        if (!(attr instanceof WebApplicationContext)) {
            throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
        }
        return (WebApplicationContext) attr;
    }
}

wac = findWebApplicationContext(); 上述这块逻辑主要是通过获取ContextAttribute的属性名去ServletContext中获取Context对象

protected WebApplicationContext findWebApplicationContext() {
    String attrName = getContextAttribute();
    if (attrName == null) {
      return null;
    }
    WebApplicationContext wac =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
    if (wac == null) {
      throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
    }
    return wac;
}

1.2.2 FrameworkServlet 中refresh源码解析

这里流程比较繁琐,重点讲述一下 wac.refresh(); 这个方法会调用AbstractApplicationContext这里类面的refresh去实现相应的逻辑,这个类具体的英文解释(implements common context functionality. Uses the Template Method design pattern) 大概意思就是说实现了一些公有的方法,通过Template Method这种设计模式实现功能,其实也就是将逻辑放到了AbstractApplicationContext中,然后子类去实现各种方法。逻辑已经由AbstractApplicationContext定好,子类不关心逻辑

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {
  //准备刷新之前调用
  protected void prepareRefresh() {
    //记录开始时间
        this.startupDate = System.currentTimeMillis();
    //改变状态
        this.closed.set(false);
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment
    //这个主要留给子类去实现
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
    //校验必须初始化的参数
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }
  //初始化一些beanFactory参数
  protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context‘s class loader etc.
    //设置classLoader
        beanFactory.setBeanClassLoader(getClassLoader());
    //设置bean表达式解析器 spring 的el 表达式
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    //使用资源编辑器来填充指定的PropertyEditorRegistry。
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
    //负责注入ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware ApplicationContext相关特性的Bean
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
    //This is intended for factory/context references that are supposed to be autowirable but are not defined as beans in the factory: e.g. a dependency of type ApplicationContext resolved to the ApplicationContext instance that the bean is living in.
    //上述英文大概意思就是定义了一个特殊的bean,但是这个bean不通过 beanFactory进行管理生命周期,beanFactory本身就是一个bean,自身管理自身就有点奇怪,所以这个方法是注册一些特殊的bean,并且可以进行注入
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Detect a LoadTimeWeaver and prepare for weaving, if found.
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

  @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
      //preparecontext之前执行的操作
            prepareRefresh();
      //告诉子类刷新bean工厂,spring boot能够做到改变一个类进行热部署,我猜可能就调用了这个刷新方法去刷新bean工厂,所以改变了一些静态变量spring boot是不会动态刷新的
            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
      //初始化一些bean工厂的参数
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
        // 增加处理servletContext的类
                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);
        //发送refresh事件
                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    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();
            }
        }
    }
}

AbstractApplicationContext这个类比较繁琐,这里只大概描述了一下大概的功能,后续文章会详细进行讲解,这里主要是讲解初始化流程

Spring 总体流程图

.png?dir=0&filepath=spring%2FsourceCode%2Fimg%2Fdipatcher+%281%29.png&oid=d32d3920eb9fa1afe65c08f70e5e3c3966ddd8e2&sha=de3a2aaf492d9bcacf82f1462d06bd50f6091186)

时间: 2024-10-29 05:12:19

Spring 源码解析之DispatcherServlet源码解析(五)的相关文章

Spring 源码解析之HandlerAdapter源码解析(二)

Spring 源码解析之HandlerAdapter源码解析(二) 前言 看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了 解决上篇文章遗留的问题 getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping ge

Spring 源码解析之ViewResolver源码解析(四)

Spring 源码解析之ViewResolver源码解析(四) 1 ViewResolver类功能解析 1.1 ViewResolver Interface to be implemented by objects that can resolve views by name. View state doesn't change during the running of the application, so implementations are free to cache views. I

spring MVC cors跨域实现源码解析 CorsConfiguration UrlBasedCorsConfigurationSource

spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就是跨域. spring MVC自4.2开始添加了跨域的支持. 跨域具体的定义请移步mozilla查看 使用案例 spring mvc中跨域使用有3种方式: 在web.xml中配置CorsFilter <filter> <filter-name>cors</filter-name> <

Spring源码解析——如何阅读源码

最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo 这篇博文你可以了解到: 1 Spring jar包以及源码使用 2 简单的spring运行示例 3 利用断点调试程序,如何快速的阅读程序[快捷键等的使用] 这次阅读的源码比较老了,是3.0.5版本的,由于正好手头有这个版本的源码,而且平时基本上也是用的这个版本Spring,因此后文的分析也都是针对

Spring源码解析——如何阅读源码(转)

最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo 这篇博文你可以了解到: 1 Spring jar包以及源码使用 2 简单的spring运行示例 3 利用断点调试程序,如何快速的阅读程序[快捷键等的使用] 这次阅读的源码比较老了,是3.0.5版本的,由于正好手头有这个版本的源码,而且平时基本上也是用的这个版本Spring,因此后文的分析也都是针对

Spring之SpringMVC前端控制器DispatcherServlet(源码)分析

1.DispatcherServlet作用说明 DispatcherServlet提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处.DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下: 1.文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析: 2.通过HandlerMapping,将请求映射到处理器(返回一个Han

Spring源码学习(三)默认标签的解析

默认标签的解析分为四种:import,alias,bean,beans,在下面函数中进行 1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 2 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { 3 importBeanDefinitionResource(ele); 4 } 5 else if (delegate.n

Spring源码学习(四)自定义标签的解析

新的一年 只争朝夕 不负韶华 加油加油?? (一)自定义便签使用 步骤:(前提要将Spring Core包加入项目中) (1)创建需要扩展的组件 (2)定义一个XSD文件描述组件内容 (3)创建一个文件,实现BeanDefinitionParse接口,用来解析XSD文件中的定义和组件定义 (4)创建一个Handler文件,扩展自NamespaceHandleSupport,目的是将组件注册到Spring容器 (5)编写Spring.Handlers和Spring.schemas文件 具体代码如下

struct2源码解读(3)之解析配置文件

struct2源码解读之解析配置文件 上篇博文讲到struct2在初始化时,在创建Dispacher之后,会Dispacher.init()中会对配置文件进行解析,下面就让我们一起探讨下struct2是如何解析配置文件的. public Dispatcher initDispatcher( HostConfig filterConfig ) {           //创建Dispacher实例         Dispatcher dispatcher = createDispatcher(f