SpringBoot的启动类代码
@SpringBootApplication
public class MyblogApplication {
public static void main(String[] args) {
SpringApplication.run(MyblogApplication.class, args);
}
}
首先在启动类这段代码中,我们点进 @SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
除了元注解外,最核心的注解有:
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
首先我们来说 @SpringBootConfiguration @EnableAutoConfiguration这两个注解
@SpringBootConfiguration 点进去之后
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Configuration
public @interface SpringBootConfiguration {
}
除了元注解外,就只有一个 @Configuration,也就是说或这个注解相当于@Configuration,所以这两个注解作用是一样的,什么作用呢?就是能够注册一些额外的Bean,并且导入一些额外的配置。@Configuration还有一个作用就是把该类变成一个配置类,不需要进行额外的XML配置。所以@SpringBootConfiguration相当于@Configuration。
继续看 @EnableAutoConfiguration,官网说这个注解是 让Spring自动去进行一些配置
点进去看
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@AutoConfigurationPackage
@import(AutoConfigurationimportSelector.class)
public @interface EnableAutoConfiguration {
}
可以看到它是由@AutoConfigurationPackage 和 @import(AutoConfigurationimportSelector.class) 组成,@AutoConfigurationPackage,作用是:让包中类以及子包中的类能够被自动扫描到Spring容器中。自动配置?它是如何配置的呢?和@import(AutoConfigurationimportSelector.class)相关
从@import(AutoConfigurationimportSelector.class) ,我们点进去看
public class AutoConfigurationimportSelector implements DeferredimportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectimports(Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return NO_importS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationmetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in meta-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
}
这个AutoConfigurationimportSelector 类中有一个方法 selectimports(Annotationmetadata annotationmetadata) ,它可以帮助扫描那些类自动去添加到程序当中。
里面还有一个方法是 getCandidateConfigurations(),它的作用是引入系统已经加载好的一些类,到底是哪些类呢?
"No auto configuration classes found in meta-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct."
从这句话中,可以看到 这个类会去找一个目录为 meta-INF/spring.factories,也就是说它会帮你加载让你去使用,也就是在meta-INF/spring.factories目录装配的,它在哪呢?
点进去看
可以发现它搬我们配置了很多类的全路径,比如WebMvc
可以看到它已经帮我们引入了进来,拿几个过来看
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,
@EnableAutoConfiguration主要作用就是帮你自动去配置,但并不是所有都是创建好的,是根据你的程序去进行决定。那我们继续来看
接着看@ComponentScan注解
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
扫描包,放入Spring容器,它在SpringBoot做了什么呢?
它帮助我们做了一个排除策略,在这里它结合@SpringBootConfiguration去使用,为什么是排除?因为不可能一上来就全部加载,内存有限。
总结@SpringBootApplication:就是说 它已经把很多东西准备好,具体是否使用取决于我们的程序或者说配置,那我们用不用?继续看这一行代码
public class MyblogApplication {
public static void main(String[] args) {
SpringApplication.run(MyblogApplication.class, args);
}
}
来看run方法有没有用到哪些自动配置的东西,比如说内置tomcat,
我们点进去 SpringApplication
class SpringApplication{
public ConfigurableApplicationContext run(String... args) {
//计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//准备上下文
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//预刷新context
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新context
refreshContext(context);
//刷次之后的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, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
}
我们关注的就是 refreshContext(context); 刷新context,点进去看
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
refresh((ApplicationContext) context);
}
追踪 refresh((ApplicationContext) context);
public class SpringApplication {
@Deprecated
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
refresh((ConfigurableApplicationContext) applicationContext);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
}
它调用了 refresh();点进去这个方法看
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
追踪refresh()
来到了 ConfigurableApplicationContext 接口
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
void refresh() throws BeansException, IllegalStateException;
}
实现该接口,重写该方法的几个类中,
点进去第一个看看
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 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);
// 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);
// 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();
}
}
}
发现,这个代码很熟悉,就是一个spring的bean的加载过程,解析SpringIOC加载过程的时候也含有这些方法,如果你看过Spring源码的话 ,应该知道这些方法都是做什么的。现在我们不关心其他的,我们来看一个方法叫做 onRefresh();方法
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}
找它的实现
我们既然要找Tomcat那就肯定跟web有关,我们可以看到有个ServletWebServerApplicationContext
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
可以看到 有一个 createWebServer() 方法,它是用来创建web容器的,而tomcat不是web容器,那它是怎么创建的呢?继续看 该方法
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
中间一行中 factory.getWebServer(getSelfInitializer());他是通过工厂的方式创建的
追踪进去
@FunctionalInterface
public interface ServletWebServerFactory {
WebServer getWebServer(ServletContextInitializer... initializers);
}
找它的实现类,要找tomcat如何创建,找tomcat相关的
进去之后,找到创建tomcat的方法
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setbaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowonFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
该过程,就是我们要找的内置tomcat以及创建tomcat的过程。



