我看的书叫做:深入理解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类型的监听器了;
回到前面的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用到的类;
它这个有个爹实现了ServletContextInitializer接口,刚刚我们也在this.webServer = factory.getWebServer(getSelfInitializer());这里的getSelfInitializer()看到,从spring的bean工厂中拿所有实现了ServletContextInitializer接口的类注册进tomcat。这个onStartup方法位于RegistrationBean中,这个方法注册了Servlet,listener和filter;
这个getSelfInitializer()下的getServletContextInitializerBeans(),
new ServletContextInitializerBeans(getBeanFactory());
最底下那个是我注册的filter