SpringMvc入口

502 阅读7分钟

我看的书叫做:深入理解Springmvc源代码

Web环境推断:

P170,这里有个判断Web环境的方法,是在SpringBoot.run方法进去的,this.webApplicationType = WebApplicationType.deduceFromClasspath(); 这个deduceFromClasspath做的事情就是推断出当前的web环境,是Reactive类型还是非Web环境,否则就是Servlet环境; 如何推断的呢,是通过class.forname一批条件来判断的,如果类加载器加载得到这些给定的类的话,那么就可以判断出Web环境;

P171页,初始化一些组件:

getSpringFactoriesInstances这个是主要的方法,往下SpringFactoriesLoader.loadFactoryNames,从Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);这里可以看到,就是利用类加载器去加载所有META-INF/spring.factories下的资源,

包括(org.springframework.boot:spring-boot-autoconfigure和org.springframework.boot:spring-boot:2.4.6下)加载文件中的所有的东西到SpringFactoriesLoader.java下的cache中(Map<String, List>);

这里实例了org.springframework.context.ApplicationContextInitializer org.springframework.context.ApplicationListener 而 Bootstrapper.class BootstrapRegistryInitializer.class在spring.factories中不存在,就没有加载了

P173页,推断main方法的启动类:

this.mainApplicationClass = deduceMainApplicationClass();这个是入口 通过代码可以知道,springboot是利用了RuntimeExceptionc创建一个异常来获取当前方法执行的调用栈信息,通过栈信息找到main入口所在的类;

private Class<?> deduceMainApplicationClass() {
   try {
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
         if ("main".equals(stackTraceElement.getMethodName())) {
            return Class.forName(stackTraceElement.getClassName());
         }
      }
   }
   catch (ClassNotFoundException ex) {
      // Swallow and continue\
   }
   return null;
}

以上就是初始化SpringApplication的一些代码步骤;

下面讨论的是SpringApplication.run方法:

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      context.setApplicationStartup(this.applicationStartup);
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      listeners.started(context);
      callRunners(context, applicationArguments);
   }\
   catch (Throwable ex) {
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

这两个方法有些重要:
第一个:

private SpringApplicationRunListeners getRunListeners(String[] args) {
   Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
   return new SpringApplicationRunListeners(logger,
         getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
         this.applicationStartup);
}

可以看到,像上边一样去cache中找SpringApplicationRunListener的类加载到容器中,即:org.springframework.boot.context.event.EventPublishingRunListener并对其进行了实例化,因此调用构造函数,并把容器中所有的listener都放入到了这个SimpleApplicationEventMulticaster广播器中; 这个this.applicationStartup默认是new DefaultApplicationStartup();

然后我们看第二个方法:starting

void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
   doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
         (step) -> {
            if (mainApplicationClass != null) {
               step.tag("mainApplicationClass", mainApplicationClass.getName());
            }
         });
}

点击那个listener.starting,这个listener就是前边SpringApplicationRunListeners构造函数传进来的EventPublishingRunListener实例,因此我们点进去,会跳转到EventPublishingRunListener中的starting方法,

public void starting(ConfigurableBootstrapContext bootstrapContext) {
   this.initialMulticaster
         .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}

这里的this.initialMulticaster就是前面EventPublishingRunListener被实例化在构造函数中创建的SimpleApplicationEventMulticaster,这里创建了一个ApplicationStartingEvent事件,SimpleApplicationEventMulticaster发布了ApplicationStartingEvent这个事件,接下来就是需要遍历监听器们找出合适的监听器去处理这种事件,并给出回应了; 点multicastEvent进去,

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

可以看到for循环这里有个getApplicationListeners(event, type)方法,这个方法在其父类AbstractApplicationEventMulticaster里,进去点击return retrieveApplicationListeners(eventType, sourceType, newRetriever);
可以看到这么一段代码:

for (ApplicationListener<?> listener : listeners) {
   if (supportsEvent(listener, eventType, sourceType)) {
      if (retriever != null) {
         filteredListeners.add(listener);
      }
      allListeners.add(listener);
   }
}

这个就是符合条件的可以处理ApplicationStartingEvent类型的监听器了;

image.png

回到前面的for循环,点击到invokeListener,最后到了SimpleApplicationEventMulticaster的doInvokeListener方法中来

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
   try {
      listener.onApplicationEvent(event);
   }
   catch (ClassCastException ex) {
      String msg = ex.getMessage();
      if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
            (event instanceof PayloadApplicationEvent &&
                  matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
         // Possibly a lambda-defined listener which we could not resolve the generic event type for
         // -> let's suppress the exception.
         Log loggerToUse = this.lazyLogger;
         if (loggerToUse == null) {
            loggerToUse = LogFactory.getLog(getClass());
            this.lazyLogger = loggerToUse;
         }
         if (loggerToUse.isTraceEnabled()) {
            loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
         }
      }
      else {
         throw ex;
      }
   }
}

点击listener.onApplicationEvent(event);我们知道这个event是ApplicationStartingEvent类型的事件,相应的监听器就会做出回应了;这个就是监听器的原理了; 接下来到这个方法ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

点进去:

第一行ConfigurableEnvironment environment = getOrCreateEnvironment();点进去,我们知道

this.webApplicationType默认是SERVLET,因此environment  = new StandardServletEnvironment();这个环境可以获取得到本地地址的环境,

然后到listeners.environmentPrepared(bootstrapContext, environment);

加载application.yml与这里有关系,创建了ApplicationEnvironmentPreparedEvent

这么一个事件;这个事件的发布会被EnvironmentPostProcessorApplicationListener它监听,它在调用到onApplicationEnvironmentPreparedEvent方法,找到ConfigDataEnvironmentPostProcessor这个类,它就是主要的处理地方了;有空可以看下这个大佬写的www.jianshu.com/p/b307d1a5c…

Banner printedBanner = printBanner(environment);就是banner.txt显示logo的地方;

context = createApplicationContext();根据this.webApplicationType创建了一个容器

ApplicationContextFactory DEFAULT = (webApplicationType) -> {
   try {
      switch (webApplicationType) {
      case SERVLET:
         return new AnnotationConfigServletWebServerApplicationContext();
      case REACTIVE:
         return new AnnotationConfigReactiveWebServerApplicationContext();
      default:
         return new AnnotationConfigApplicationContext();
      }
   }
   catch (Exception ex) {
      throw new IllegalStateException("Unable create a default ApplicationContext instance, "
            + "you may need a custom ApplicationContextFactory", ex);
   }
};

prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); 就是给应用上下文context设置一些属性之类的;

refreshContext(context);这个就比较重要来了,刷新上下文,一直往下就会到

ServletWebServerApplicationContext类的
public final void refresh() throws BeansException, IllegalStateException {
   try {
      super.refresh();
   }
   catch (RuntimeException ex) {
      WebServer webServer = this.webServer;
      if (webServer != null) {
         webServer.stop();
      }
      throw ex;
   }
}

可以看到,它调用了父类的refresh,这里就是加载spring的最主要的方法了,什么beanfactory,beanpostproccessor都是在这里面加载初始化的,bean工厂啊之类的;

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);
         beanPostProcess.end();

         // 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);

         // 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();
         contextRefresh.end();
      }
   }
}
spring相关的东西,自己去补习吧

然后到了onRefresh();这个方法,它会交由子类去实现,spring预留的一个方法,点击回

ServletWebServerApplicationContext,

@Override
protected void onRefresh() {
   super.onRefresh();
   try {
      createWebServer();
   }
   catch (Throwable ex) {
      throw new ApplicationContextException("Unable to start web server", ex);
   }
}

看方法createWebServer();这里面就包括了tomcat的配置
this.webServer = factory.getWebServer(getSelfInitializer());
ServletContextInitializer这个接口十分的重要,用于注册到tomcat中Servlet,listener和filter的一个接口这个getSelfInitializer()其实就是去spring的兵工厂中获取ServletContextInitializer的接口实现类;一直点进去,可以看到addServletContextInitializerBeans(beanFactory);


private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
   for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
      for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,
            initializerType)) {
         addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
      }
   }
}

private <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type,
      Set<?> excludes) {
   String[] names = beanFactory.getBeanNamesForType(type, true, false);
   Map<String, T> map = new LinkedHashMap<>();
   for (String name : names) {
      if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
         T bean = beanFactory.getBean(name, type);
         if (!excludes.contains(bean)) {
            map.put(name, bean);
         }
      }
   }
   List<Entry<String, T>> beans = new ArrayList<>(map.entrySet());
   beans.sort((o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue()));
   return beans;
}

可以看到就是从bean工厂里面去查找ServletContextInitializer接口,但是tomcat去启动onStartUp()的主要位置不是这里,这里只是去启动bean工厂中的ServletContextInitializer接口;

  真正的位置是在this.webServer = factory.getWebServer(getSelfInitializer()); getWebServer中

prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);

prepareContext方法下:
configureContext(context, initializersToUse);
TomcatStarter starter = new TomcatStarter(initializers);
这里创建了一个TomcatStarter,在启动tomcat的时候就会调用它,那么在tomcat什么时候start呢? getTomcatWebServer方法下:

protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
   return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}

initialize();

this.tomcat.start();

startInternal();

StandardContext类下的startInternal();

for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
    initializers.entrySet()) {
    try {
        entry.getKey().onStartup(entry.getValue(),
                getServletContext());
    } catch (ServletException e) {
        log.error(sm.getString("standardContext.sciFail"), e);
        ok = false;
        break;
    }
}

可以看到onStartup的真正入口在这里;
那么dispatcherServlet是如何被注册进tomcat的servlet中的呢?
Shift+Shift搜索DispatcherServletAutoConfiguration,这是一个注册bean的类,

@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {

   @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
   public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
      DispatcherServlet dispatcherServlet = new DispatcherServlet();
      dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
      dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
      dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
      dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
      dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
      return dispatcherServlet;
   }

   @Bean
   @ConditionalOnBean(MultipartResolver.class)\
   @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
   public MultipartResolver multipartResolver(MultipartResolver resolver) {
      // Detect if the user has created a MultipartResolver but named it incorrectly
      return resolver;
   }

}
可以主要到 dispatcherServlet类被注册进了spring的bean工厂中;

 


@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@Import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {

   @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
   @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
   public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
         WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
      DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
            webMvcProperties.getServlet().getPath());
      registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
      registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
      multipartConfig.ifAvailable(registration::setMultipartConfig);
      return registration;
   }
}

这个bean的名字叫做DispatcherServletRegistrationBean,显而易见名字就是注册进Servlet用到的类;

image.png

它这个有个爹实现了ServletContextInitializer接口,刚刚我们也在this.webServer = factory.getWebServer(getSelfInitializer());这里的getSelfInitializer()看到,从spring的bean工厂中拿所有实现了ServletContextInitializer接口的类注册进tomcat。这个onStartup方法位于RegistrationBean中,这个方法注册了Servlet,listener和filter;

这个getSelfInitializer()下的getServletContextInitializerBeans(),
new ServletContextInitializerBeans(getBeanFactory());
最底下那个是我注册的filter image.png