Spring boot基本使用及 stater机制原理_踩踩踩从踩的博客-CSDN博客
前面文章对于springboot得基本使用以及stater机制 以及autoconfig 做了一个解读,如何手写一个starter的包,对于 自动装配 解读,有了个大概的思维;这篇文章继续讲解SpringBoot的核心源码 ,然后深入的解析整个Springboot怎么快速的构建项目 并管理我们的依赖jar包等等。
@SpringBootApplication
public class DeviceManagerApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DeviceManagerApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(DeviceManagerApplication.class);
}
}
对于springboot 只需要运行run方法就可以将我们的程序给运行起来。
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified source using default settings.
* @param primarySource the primary source to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class> primarySource, String... args) {
return run(new Class>[] { primarySource }, args);
}
该类,该类可用于从Java main引导和启动Spring应用程序方法。默认情况下,类将执行以下步骤来引导申请:
下面的步骤 核心逻辑 就是 创建 applicationcontext 实例、
并且 注册 CommandLinePropertySource
激活 CommandLineRunner 这个接口 用于指示当bean包含在 一个{@link SpringApplication}。可以定义多个{@link CommandLineRunner}bean 在同一个应用程序上下文中,可以使用{@link ordered} 接口或{@link Order@Order}注释。 也就是说可以 查看当前springapplication创建了那些bean.
/**一:注释上的重要信息: 1、primary sources:application context从primarySource加载beans
2、创建的SpringApplication实例在调用它的run(String...)方法前,可对其进行定制化设置 可以进行哪些设置?看类中提供的public方法。
* Create a new {@link SpringApplication} instance. The application context will load * beans from the specified primary sources (see {@link SpringApplication class- level}
* documentation for details. The instance can be customized before calling * {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
//二、构造方法中的逻辑:
this.resourceLoader = resourceLoader;
// 1、一定要指定primarySources
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 2、deduce(推断)web类型(servlet、reactive、NoWeb)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 3、从META-INF/spring.factories中获取
ApplicationContextInitializer setInitializers((Collection)
getSpringFactoriesInstances( ApplicationContextInitializer.class));
// 4、从META-INF/spring.factories中获取
ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 5、推断执行的main方法的定义类 this.mainApplicationClass = deduceMainApplicationClass();
}
webApplicationType 探测分配 是什么类型的 项目 ,其实是很简单的。 主要是判断 是否存在 父类
创建获取实例, 将监听器都放进去就可以了。
在初始化的时候会去调用
以及ApplicationListener 是作为监听器存在的。
/** 一:注释上的重要信息: 运行Spring application,创建并刷新一个 ApplicationContext
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 二、方法中的逻辑:
// 1 StopWatch开启计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<> ();
// 这是设置系统属性java.awt.headless,请百度了解 java.awt.headless的用途。
configureHeadlessProperty();
// 2、获取到 META-INF/spring.factories中配置的SpringApplicationRunListener
// 疑问:又出一个Listener,这个SpringApplicationRunListener是监听什么的?
// 通过它的接口定义、注释了解它的用途
SpringApplicationRunListeners listeners = getRunListeners(args);
// 这里就调用它的starting()
listeners.starting();
try {
// 命令行参数包装为了ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments( args);
// 3、准备好了Environment,此刻Environment中都有哪些配置参数了?
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 4、打印springboot LOGo图标
Banner printedBanner = printBanner(environment);
// 5、创建ApplicationContext context = createApplicationContext();
// 6、获取到 META-INF/spring.factories中配置的SpringBootExceptionReporter
exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] {
ConfigurableApplicationContext.class }, context);
// 7、准备ApplicationContext
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 8、刷新ApplicationContext
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch);
}//
9、发布started事件 listeners.started(context);
// 10、执行所有的Runners
callRunners(context, applicationArguments);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 11、发布running中事件
listeners.running(context);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
// 12、返回ok的ConfigurableApplicationContext return context;
}
configureHeadlessProperty 方法 该方法只做了一件事:设置了一个名为java.awt.headless的系统属性
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
SpringApplicationRunListeners 返回的所有 SpringApplicationRunListener 监听器 , 这里面就是 监听 它失败 等等状态。
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);
}
准备参数 DefaultApplicationArguments 本身需要处理
触发RunListener环境准备完成回调
根据类型加载 不同的参数。
ConfigurationPropertySources
包括各种 的配置启用的profiles 也可以指定 profiles 所以可以取出来做处理。
环境上准备 就有的这个。 参数配置
这里面就是 加载的配置参数。
会将事件给发布出来。
完整的加载过程。
在新版本中是添加
这里最终调用 的applicationcontext. refresh方法。
这个加载是整个 创建基础。
// 3、从META-INF/spring.factories中获取ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
这个方法 是可以加载 spring.factories
但是对于 EnableAutoconfiguration 的加载 是在那里去加载的,暂时不知道。
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
public class AnnotationConfigServletWebServerApplicationContextextends ServletWebServerApplicationContext implements AnnotationConfigRegistry {}
@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);
}