• springmvc 启动过程


    dispatcher-servlet.xml

    1. "1.0" encoding="UTF-8"?>
    2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    5. version="4.0">
    6. <context-param>
    7. <param-name>contextConfigLocationparam-name>
    8. <param-value>/WEB-INF/applicationContext.xmlparam-value>
    9. context-param>
    10. <listener>
    11. <listener-class> org.springframework.web.context.ContextLoaderListenerlistener-class>
    12. listener>
    13. <servlet>
    14. <servlet-name>dispatcherservlet-name>
    15. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    16. <load-on-startup>1load-on-startup>
    17. servlet>
    18. <servlet-mapping>
    19. <servlet-name>dispatcherservlet-name>
    20. <url-pattern>/url-pattern>
    21. servlet-mapping>
    22. web-app>

     
    

    ContextLoader.java

    /**
     * Name of the class path resource (relative to the ContextLoader class)
     * that defines ContextLoader's default strategy names.
     */
    private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
    static {
       // Load default strategy implementations from properties file.
       // This is currently strictly internal and not meant to be customized
       // by application developers.
       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());
       }
    }
    

    ContextLoader 加载ContextLoader.properties文件,内容如下

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

    通过继承关系可以看到

    ContextLoaderListener 继承了ServletContextListener 因此看contextInitialized()方法如何初始化initWebApplicationContext,而initWebApplicationContext()在ContextLoader里实现。

    ContextLoaderListener#contextInitialized()

    1. public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    2. public ContextLoaderListener() {
    3. }
    4. public ContextLoaderListener(WebApplicationContext context) {
    5. super(context);
    6. }
    7. /**
    8. * Initialize the root web application context.
    9. */
    10. @Override
    11. public void contextInitialized(ServletContextEvent event) {
    12. initWebApplicationContext(event.getServletContext());
    13. }
    14. }

    ContextLoader#initWebApplicationContext();

    1. ContextLoader.java
    2. /**
    3. * The root WebApplicationContext instance that this loader manages.
    4. */
    5. @Nullable
    6. private WebApplicationContext context;
    7. /**
    8. * Initialize Spring's web application context for the given servlet context,
    9. * using the application context provided at construction time, or creating a new one
    10. * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
    11. * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
    12. * @param servletContext current servlet context
    13. * @return the new WebApplicationContext
    14. * @see #ContextLoader(WebApplicationContext)
    15. * @see #CONTEXT_CLASS_PARAM
    16. * @see #CONFIG_LOCATION_PARAM
    17. */
    18. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    19. if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
    20. throw new IllegalStateException(
    21. "Cannot initialize context because there is already a root application context present - " +
    22. "check whether you have multiple ContextLoader* definitions in your web.xml!");
    23. }
    24. servletContext.log("Initializing Spring root WebApplicationContext");
    25. Log logger = LogFactory.getLog(ContextLoader.class);
    26. if (logger.isInfoEnabled()) {
    27. logger.info("Root WebApplicationContext: initialization started");
    28. }
    29. long startTime = System.currentTimeMillis();
    30. try {
    31. // Store context in local instance variable, to guarantee that
    32. // it is available on ServletContext shutdown.
    33. if (this.context == null) {
    34. //根据配置文件实例化xmlwebApplicationContext
    35. this.context = createWebApplicationContext(servletContext);
    36. }
    37. if (this.context instanceof ConfigurableWebApplicationContext) {
    38. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
    39. if (!cwac.isActive()) {
    40. // The context has not yet been refreshed -> provide services such as
    41. // setting the parent context, setting the application context id, etc
    42. if (cwac.getParent() == null) {
    43. // The context instance was injected without an explicit parent ->
    44. // determine parent for root web application context, if any.
    45. ApplicationContext parent = loadParentContext(servletContext);
    46. cwac.setParent(parent);
    47. }
    48. //调用spring ioc容器完成初始化
    49. configureAndRefreshWebApplicationContext(cwac, servletContext);
    50. }
    51. }
    52. // 将上下文放在servletContext中
    53. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    54. ClassLoader ccl = Thread.currentThread().getContextClassLoader();
    55. if (ccl == ContextLoader.class.getClassLoader()) {
    56. currentContext = this.context;
    57. }
    58. else if (ccl != null) {
    59. currentContextPerThread.put(ccl, this.context);
    60. }
    61. if (logger.isInfoEnabled()) {
    62. long elapsedTime = System.currentTimeMillis() - startTime;
    63. logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
    64. }
    65. return this.context;
    66. }
    67. catch (RuntimeException | Error ex) {
    68. logger.error("Context initialization failed", ex);
    69. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
    70. throw ex;
    71. }
    72. }


        执行完上述后,由

    Tomcat服务器继续执行后续代码过滤器filterStart、然后执行配置文件的 DispatcherServlet

    1. StandardContext.java
    2. /**
    3. * Start this component and implement the requirements
    4. * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
    5. *
    6. * @exception LifecycleException if this component detects a fatal error
    7. * that prevents this component from being used
    8. */
    9. @Override
    10. protected synchronized void startInternal() throws LifecycleException {
    11. ......
    12. // Configure and call application event listeners
    13. if (ok) {
    14. //执行listener
    15. if (!listenerStart()) {
    16. log.error(sm.getString("standardContext.listenerFail"));
    17. ok = false;
    18. }
    19. }
    20. // Check constraints for uncovered HTTP methods
    21. // Needs to be after SCIs and listeners as they may programmatically
    22. // change constraints
    23. if (ok) {
    24. checkConstraintsForUncoveredMethods(findConstraints());
    25. }
    26. try {
    27. // Start manager
    28. Manager manager = getManager();
    29. if ((manager != null) && (manager instanceof Lifecycle)) {
    30. ((Lifecycle) manager).start();
    31. }
    32. } catch(Exception e) {
    33. log.error(sm.getString("standardContext.managerFail"), e);
    34. ok = false;
    35. }
    36. // Configure and call application filters
    37. if (ok) {
    38. //执行filter
    39. if (!filterStart()) {
    40. log.error(sm.getString("standardContext.filterFail"));
    41. ok = false;
    42. }
    43. }
    44. // Load and initialize all "load on startup" servlets
    45. //执行servlet
    46. if (ok) {
    47. if (!loadOnStartup(findChildren())){
    48. log.error(sm.getString("standardContext.servletFail"));
    49. ok = false;
    50. }
    51. }
    52. ......
    53. }

    执行类StandardWarpper# private synchronized void initServlet(Servlet servlet)

    1. private synchronized void initServlet(Servlet servlet)
    2. throws ServletException {
    3. if (instanceInitialized && !singleThreadModel) return;
    4. // Call the initialization method of this servlet
    5. try {
    6. instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
    7. servlet);
    8. if( Globals.IS_SECURITY_ENABLED) {
    9. boolean success = false;
    10. try {
    11. Object[] args = new Object[] { facade };
    12. SecurityUtil.doAsPrivilege("init",
    13. servlet,
    14. classType,
    15. args);
    16. success = true;
    17. } finally {
    18. if (!success) {
    19. // destroy() will not be called, thus clear the reference now
    20. SecurityUtil.remove(servlet);
    21. }
    22. }
    23. } else {
    24. //调用servlet.init();
    25. servlet.init(facade);
    26. }
    27. instanceInitialized = true;
    28. instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
    29. servlet);
    30. } catch (UnavailableException f) {
    31. instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
    32. servlet, f);
    33. unavailable(f);
    34. throw f;
    35. } catch (ServletException f) {
    36. instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
    37. servlet, f);
    38. // If the servlet wanted to be unavailable it would have
    39. // said so, so do not call unavailable(null).
    40. throw f;
    41. } catch (Throwable f) {
    42. ExceptionUtils.handleThrowable(f);
    43. getServletContext().log("StandardWrapper.Throwable", f );
    44. instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
    45. servlet, f);
    46. // If the servlet wanted to be unavailable it would have
    47. // said so, so do not call unavailable(null).
    48. throw new ServletException
    49. (sm.getString("standardWrapper.initException", getName()), f);
    50. }
    51. }


    由继承图可以看到,GenericServlet的init()方法由HttpServletBean的init()实现。

    1. GenericServlet.java
    2. /**
    3. * Called by the servlet container to indicate to a servlet that the servlet
    4. * is being placed into service. See {@link Servlet#init}.
    5. *

    6. * This implementation stores the {@link ServletConfig} object it receives
    7. * from the servlet container for later use. When overriding this form of
    8. * the method, call super.init(config).
    9. *
    10. * @param config
    11. * the ServletConfig object that contains
    12. * configuration information for this servlet
    13. * @exception ServletException
    14. * if an exception occurs that interrupts the servlet's
    15. * normal operation
    16. * @see UnavailableException
    17. */
    18. @Override
    19. public void init(ServletConfig config) throws ServletException {
    20. this.config = config;
    21. this.init();
    22. }
    23. /**
    24. * A convenience method which can be overridden so that there's no need to
    25. * call super.init(config).
    26. *

    27. * Instead of overriding {@link #init(ServletConfig)}, simply override this
    28. * method and it will be called by
    29. * GenericServlet.init(ServletConfig config). The
    30. * ServletConfig object can still be retrieved via
    31. * {@link #getServletConfig}.
    32. *
    33. * @exception ServletException
    34. * if an exception occurs that interrupts the servlet's
    35. * normal operation
    36. */
    37. public void init() throws ServletException {
    38. // NOOP by default
    39. }

    而GenericServlet其自身this.init()方法是空的,需要子类HttpServletBean实现init()

    1. HttpServletBean.java
    2. /**
    3. * Map config parameters onto bean properties of this servlet, and
    4. * invoke subclass initialization.
    5. * @throws ServletException if bean properties are invalid (or required
    6. * properties are missing), or if subclass initialization fails.
    7. */
    8. @Override
    9. public final void init() throws ServletException {
    10. // Set bean properties from init parameters.
    11. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    12. if (!pvs.isEmpty()) {
    13. try {
    14. BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
    15. ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
    16. bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
    17. initBeanWrapper(bw);
    18. bw.setPropertyValues(pvs, true);
    19. }
    20. catch (BeansException ex) {
    21. if (logger.isErrorEnabled()) {
    22. logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
    23. }
    24. throw ex;
    25. }
    26. }
    27. // Let subclasses do whatever initialization they like.
    28. initServletBean();
    29. }

    FrameworkServlet#initServletBean()

    1. FrameworkServlet.java
    2. /**
    3. * Overridden method of {@link HttpServletBean}, invoked after any bean properties
    4. * have been set. Creates this servlet's WebApplicationContext.
    5. */
    6. @Override
    7. protected final void initServletBean() throws ServletException {
    8. getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
    9. if (logger.isInfoEnabled()) {
    10. logger.info("Initializing Servlet '" + getServletName() + "'");
    11. }
    12. long startTime = System.currentTimeMillis();
    13. try {
    14. //创建webApplicationContext,默认由XmlWebApplicationContext实现
    15. this.webApplicationContext = initWebApplicationContext();
    16. //空实现
    17. initFrameworkServlet();
    18. }
    19. catch (ServletException | RuntimeException ex) {
    20. logger.error("Context initialization failed", ex);
    21. throw ex;
    22. }
    23. if (logger.isDebugEnabled()) {
    24. String value = this.enableLoggingRequestDetails ?
    25. "shown which may lead to unsafe logging of potentially sensitive data" :
    26. "masked to prevent unsafe logging of potentially sensitive data";
    27. logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
    28. "': request parameters and headers will be " + value);
    29. }
    30. if (logger.isInfoEnabled()) {
    31. logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
    32. }
    33. }

    initWebApplicationContext()方法由ContextLoader.java实现。

    1. ContextLoader.java
    2. /**
    3. * Initialize Spring's web application context for the given servlet context,
    4. * using the application context provided at construction time, or creating a new one
    5. * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
    6. * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
    7. * @param servletContext current servlet context
    8. * @return the new WebApplicationContext
    9. * @see #ContextLoader(WebApplicationContext)
    10. * @see #CONTEXT_CLASS_PARAM
    11. * @see #CONFIG_LOCATION_PARAM
    12. */
    13. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    14. if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
    15. throw new IllegalStateException(
    16. "Cannot initialize context because there is already a root application context present - " +
    17. "check whether you have multiple ContextLoader* definitions in your web.xml!");
    18. }
    19. servletContext.log("Initializing Spring root WebApplicationContext");
    20. Log logger = LogFactory.getLog(ContextLoader.class);
    21. if (logger.isInfoEnabled()) {
    22. logger.info("Root WebApplicationContext: initialization started");
    23. }
    24. long startTime = System.currentTimeMillis();
    25. try {
    26. // Store context in local instance variable, to guarantee that
    27. // it is available on ServletContext shutdown.
    28. if (this.context == null) {
    29. this.context = createWebApplicationContext(servletContext);
    30. }
    31. if (this.context instanceof ConfigurableWebApplicationContext) {
    32. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
    33. if (!cwac.isActive()) {
    34. // The context has not yet been refreshed -> provide services such as
    35. // setting the parent context, setting the application context id, etc
    36. if (cwac.getParent() == null) {
    37. // The context instance was injected without an explicit parent ->
    38. // determine parent for root web application context, if any.
    39. ApplicationContext parent = loadParentContext(servletContext);
    40. cwac.setParent(parent);
    41. }
    42. configureAndRefreshWebApplicationContext(cwac, servletContext);
    43. }
    44. }
    45. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    46. ClassLoader ccl = Thread.currentThread().getContextClassLoader();
    47. if (ccl == ContextLoader.class.getClassLoader()) {
    48. currentContext = this.context;
    49. }
    50. else if (ccl != null) {
    51. currentContextPerThread.put(ccl, this.context);
    52. }
    53. if (logger.isInfoEnabled()) {
    54. long elapsedTime = System.currentTimeMillis() - startTime;
    55. logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
    56. }
    57. return this.context;
    58. }
    59. catch (RuntimeException | Error ex) {
    60. logger.error("Context initialization failed", ex);
    61. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
    62. throw ex;
    63. }
    64. }
    this.context = createWebApplicationContext(servletContext);
    
    1. /**
    2. * Instantiate the root WebApplicationContext for this loader, either the
    3. * default context class or a custom context class if specified.
    4. *

      This implementation expects custom contexts to implement the

    5. * {@link ConfigurableWebApplicationContext} interface.
    6. * Can be overridden in subclasses.
    7. *

      In addition, {@link #customizeContext} gets called prior to refreshing the

    8. * context, allowing subclasses to perform custom modifications to the context.
    9. * @param sc current servlet context
    10. * @return the root WebApplicationContext
    11. * @see ConfigurableWebApplicationContext
    12. */
    13. protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
    14. Class contextClass = determineContextClass(sc);
    15. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
    16. throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
    17. "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
    18. }
    19. //实例化
    20. return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    21. }


       configureAndRefreshWebApplicationContext(wac);

    1. protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    2. if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
    3. // The application context id is still set to its original default value
    4. // -> assign a more useful id based on available information
    5. String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
    6. if (idParam != null) {
    7. wac.setId(idParam);
    8. }
    9. else {
    10. // Generate default id...
    11. wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
    12. ObjectUtils.getDisplayString(sc.getContextPath()));
    13. }
    14. }
    15. wac.setServletContext(sc);
    16. String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
    17. if (configLocationParam != null) {
    18. wac.setConfigLocation(configLocationParam);
    19. }
    20. // The wac environment's #initPropertySources will be called in any case when the context
    21. // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    22. // use in any post-processing or initialization that occurs below prior to #refresh
    23. ConfigurableEnvironment env = wac.getEnvironment();
    24. if (env instanceof ConfigurableWebEnvironment) {
    25. ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    26. }
    27. customizeContext(sc, wac);
    28. //调用AbstractApplicationContext refresh()方法
    29. wac.refresh();
    30. }

    AbstractApplicationContext#refresh()

    1. @Override
    2. public void refresh() throws BeansException, IllegalStateException {
    3. synchronized (this.startupShutdownMonitor) {
    4. // Prepare this context for refreshing.
    5. prepareRefresh();
    6. // Tell the subclass to refresh the internal bean factory.
    7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    8. // Prepare the bean factory for use in this context.
    9. prepareBeanFactory(beanFactory);
    10. try {
    11. // Allows post-processing of the bean factory in context subclasses.
    12. postProcessBeanFactory(beanFactory);
    13. // Invoke factory processors registered as beans in the context.
    14. invokeBeanFactoryPostProcessors(beanFactory);
    15. // Register bean processors that intercept bean creation.
    16. registerBeanPostProcessors(beanFactory);
    17. // Initialize message source for this context.
    18. initMessageSource();
    19. // Initialize event multicaster for this context.
    20. initApplicationEventMulticaster();
    21. // Initialize other special beans in specific context subclasses.
    22. onRefresh();
    23. // Check for listener beans and register them.
    24. registerListeners();
    25. // Instantiate all remaining (non-lazy-init) singletons.
    26. finishBeanFactoryInitialization(beanFactory);
    27. // Last step: publish corresponding event.
    28. finishRefresh();
    29. }
    30. catch (BeansException ex) {
    31. if (logger.isWarnEnabled()) {
    32. logger.warn("Exception encountered during context initialization - " +
    33. "cancelling refresh attempt: " + ex);
    34. }
    35. // Destroy already created singletons to avoid dangling resources.
    36. destroyBeans();
    37. // Reset 'active' flag.
    38. cancelRefresh(ex);
    39. // Propagate exception to caller.
    40. throw ex;
    41. }
    42. finally {
    43. // Reset common introspection caches in Spring's core, since we
    44. // might not ever need metadata for singleton beans anymore...
    45. resetCommonCaches();
    46. }
    47. }
    48. }


             // Last step: publish corresponding event.
             finishRefresh();

        

    1. AbstractApplicationContext.java
    2. /**
    3. * Finish the refresh of this context, invoking the LifecycleProcessor's
    4. * onRefresh() method and publishing the
    5. * {@link org.springframework.context.event.ContextRefreshedEvent}.
    6. */
    7. protected void finishRefresh() {
    8. // Clear context-level resource caches (such as ASM metadata from scanning).
    9. clearResourceCaches();
    10. // Initialize lifecycle processor for this context.
    11. initLifecycleProcessor();
    12. // Propagate refresh to lifecycle processor first.
    13. getLifecycleProcessor().onRefresh();
    14. // Publish the final event.
    15. publishEvent(new ContextRefreshedEvent(this));
    16. // Participate in LiveBeansView MBean, if active.
    17. LiveBeansView.registerApplicationContext(this);
    18. }
    19. /**
    20. * Publish the given event to all listeners.
    21. *

      Note: Listeners get initialized after the MessageSource, to be able

    22. * to access it within listener implementations. Thus, MessageSource
    23. * implementations cannot publish events.
    24. * @param event the event to publish (may be application-specific or a
    25. * standard framework event)
    26. */
    27. @Override
    28. public void publishEvent(ApplicationEvent event) {
    29. publishEvent(event, null);
    30. }
    31. /**
    32. * Publish the given event to all listeners.
    33. * @param event the event to publish (may be an {@link ApplicationEvent}
    34. * or a payload object to be turned into a {@link PayloadApplicationEvent})
    35. * @param eventType the resolved event type, if known
    36. * @since 4.2
    37. */
    38. protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    39. Assert.notNull(event, "Event must not be null");
    40. // Decorate event as an ApplicationEvent if necessary
    41. ApplicationEvent applicationEvent;
    42. if (event instanceof ApplicationEvent) {
    43. applicationEvent = (ApplicationEvent) event;
    44. }
    45. else {
    46. applicationEvent = new PayloadApplicationEvent<>(this, event);
    47. if (eventType == null) {
    48. eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
    49. }
    50. }
    51. // Multicast right now if possible - or lazily once the multicaster is initialized
    52. if (this.earlyApplicationEvents != null) {
    53. this.earlyApplicationEvents.add(applicationEvent);
    54. }
    55. else {
    56. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    57. }
    58. // Publish event via parent context as well...
    59. if (this.parent != null) {
    60. if (this.parent instanceof AbstractApplicationContext) {
    61. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    62. }
    63. else {
    64. this.parent.publishEvent(event);
    65. }
    66. }
    67. }


    getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

    SimpleApplicationEventMulticaster.java

    1. SimpleApplicationEventMulticaster.java
    2. @Override
    3. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    4. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    5. Executor executor = getTaskExecutor();
    6. for (ApplicationListener listener : getApplicationListeners(event, type)) {
    7. if (executor != null) {
    8. executor.execute(() -> invokeListener(listener, event));
    9. }
    10. else {
    11. invokeListener(listener, event);
    12. }
    13. }
    14. }
    15. private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
    16. return ResolvableType.forInstance(event);
    17. }


          else {
             invokeListener(listener, event);
        }

    1. /**
    2. * Invoke the given listener with the given event.
    3. * @param listener the ApplicationListener to invoke
    4. * @param event the current event to propagate
    5. * @since 4.1
    6. */
    7. protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
    8. ErrorHandler errorHandler = getErrorHandler();
    9. if (errorHandler != null) {
    10. try {
    11. doInvokeListener(listener, event);
    12. }
    13. catch (Throwable err) {
    14. errorHandler.handleError(err);
    15. }
    16. }
    17. else {
    18. doInvokeListener(listener, event);
    19. }
    20. }


       else {
          doInvokeListener(listener, event);
       }

     

    1. @SuppressWarnings({"rawtypes", "unchecked"})
    2. private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    3. try {
    4. listener.onApplicationEvent(event);
    5. }
    6. catch (ClassCastException ex) {
    7. String msg = ex.getMessage();
    8. if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
    9. // Possibly a lambda-defined listener which we could not resolve the generic event type for
    10. // -> let's suppress the exception and just log a debug message.
    11. Log logger = LogFactory.getLog(getClass());
    12. if (logger.isTraceEnabled()) {
    13. logger.trace("Non-matching event type for listener: " + listener, ex);
    14. }
    15. }
    16. else {
    17. throw ex;
    18. }
    19. }
    20. }


       try {
          listener.onApplicationEvent(event);
       }

     

    SourceFilteringListener.java

    1. @Override
    2. public void onApplicationEvent(ApplicationEvent event) {
    3. if (event.getSource() == this.source) {
    4. onApplicationEventInternal(event);
    5. }
    6. }
    7. /**
    8. * Actually process the event, after having filtered according to the
    9. * desired event source already.
    10. *

      The default implementation invokes the specified delegate, if any.

    11. * @param event the event to process (matching the specified source)
    12. */
    13. protected void onApplicationEventInternal(ApplicationEvent event) {
    14. if (this.delegate == null) {
    15. throw new IllegalStateException(
    16. "Must specify a delegate object or override the onApplicationEventInternal method");
    17. }
    18. //这个this.delegate又委托GenericApplicationListenerAdapter类的onApplicationEvent方法
    19. this.delegate.onApplicationEvent(event);
    20. }
    1. GenericApplicationListenerAdapter.java
    2. @Override
    3. public void onApplicationEvent(ApplicationEvent event) {
    4. //这个this.delegate又委托ContextRefreshListener类的onApplicationEvent方法
    5. this.delegate.onApplicationEvent(event);
    6. }

    事件源XmlWebApplicationContext

    事件ContextRefreshedEvent

    监听器 ContextRefreshListener

    FrameworkServlet.java

    1. FrameworkServlet.java
    2. /**
    3. * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
    4. * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
    5. */
    6. //内部类
    7. private class ContextRefreshListener implements ApplicationListener {
    8. @Override
    9. public void onApplicationEvent(ContextRefreshedEvent event) {
    10. FrameworkServlet.this.onApplicationEvent(event);
    11. }
    12. }
    1. FrameworkServlet.java
    2. /**
    3. * Callback that receives refresh events from this servlet's WebApplicationContext.
    4. *

      The default implementation calls {@link #onRefresh},

    5. * triggering a refresh of this servlet's context-dependent state.
    6. * @param event the incoming ApplicationContext event
    7. */
    8. public void onApplicationEvent(ContextRefreshedEvent event) {
    9. this.refreshEventReceived = true;
    10. synchronized (this.onRefreshMonitor) {
    11. onRefresh(event.getApplicationContext());
    12. }
    13. }
    14. /**
    15. * Template method which can be overridden to add servlet-specific refresh work.
    16. * Called after successful context refresh.
    17. *

      This implementation is empty.

    18. * @param context the current WebApplicationContext
    19. * @see #refresh()
    20. */
    21. protected void onRefresh(ApplicationContext context) {
    22. // For subclasses: do nothing by default.
    23. }

    因为DispatcherServlet extends FrameworkServlet,所以执行子类DispatcherServlet#onRefresh()

    1. DispatcherServlet.java
    2. /**
    3. * This implementation calls {@link #initStrategies}.
    4. */
    5. @Override
    6. protected void onRefresh(ApplicationContext context) {
    7. initStrategies(context);
    8. }
    9. /**
    10. * Initialize the strategy objects that this servlet uses.
    11. *

      May be overridden in subclasses in order to initialize further strategy objects.

    12. */
    13. protected void initStrategies(ApplicationContext context) {
    14. initMultipartResolver(context);
    15. initLocaleResolver(context);
    16. initThemeResolver(context);
    17. initHandlerMappings(context);
    18. initHandlerAdapters(context);
    19. initHandlerExceptionResolvers(context);
    20. initRequestToViewNameTranslator(context);
    21. initViewResolvers(context);
    22. initFlashMapManager(context);
    23. }
    initStrategies就是springmvc大家熟悉的流程了。。。
    

  • 相关阅读:
    C#静态类和静态类成员
    博客摘录「 hyperf使用jwt的redis储存驱动实现用户token认证」2024年4月9日
    分段读取csv文件并可视化处理
    《More Effective C++》- 极精简版 11-20条
    3、Elasticsearch功能使用
    2024 MCM数学建模美赛2024年A题复盘,思路与经验分享:资源可用性与性别比例 | 七鳃鳗的性别比例变化对生态系统稳定性的影响(四)
    数据驱动智能护理:看AI如何塑造医疗领域,为灰暗夕阳带来新的曙光
    elasticsearch5-RestAPI操作
    Vuex,Vue-router
    Kafka消费者重平衡
  • 原文地址:https://blog.csdn.net/SOMECT/article/details/126957785