SpringBoot 启动方法run()源码赏析
程序员文章站
2022-05-09 18:32:33
入口通常一个简单的SpringBoot基础项目我们会有如下代码@SpringBootApplication@RestController@RequestMapping("/")public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}值得关注的有SpringApplication.run以及注解@Spri...
入口
通常一个简单的SpringBoot基础项目我们会有如下代码
@SpringBootApplication
@RestController
@RequestMapping("/")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
值得关注的有SpringApplication.run以及注解@SpringBootApplication
run方法
public ConfigurableApplicationContext run(String... args) {
// 秒表
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 监听器启动
listeners.starting();
try {
// application 启动参数列表
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置忽略的bean信息
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 创建应用上下文
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备上下文,装配bean
prepareContext(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, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 监听器正式运行
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
getRunListeners
获取监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 获取 Spring Factory 实例对象
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 读取 spring.factories
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建SpringFactory实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
/**
* 排序 {@link Ordered}
*/
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
createSpringFactoriesInstances
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
// 初始化
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
// 通过名字创建类的class对象
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
// 构造器获取
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 创建具体实例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
// 加入实例表中
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
printBanner
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
// 创建打印器
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
// 输出
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
// 输出
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
Banner banner = getBanner(environment);
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
}
最终输出内容类:org.springframework.boot.SpringBootBanner
class SpringBootBanner implements Banner {
private static final String[] BANNER = { "", " . ____ _ __ _ _",
" /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
" \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
" =========|_|==============|___/=/_/_/_/" };
private static final String SPRING_BOOT = " :: Spring Boot :: ";
private static final int STRAP_LINE_SIZE = 42;
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
for (String line : BANNER) {
printStream.println(line);
}
String version = SpringBootVersion.getVersion();
version = (version != null) ? " (v" + version + ")" : "";
StringBuilder padding = new StringBuilder();
while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
padding.append(" ");
}
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
AnsiStyle.FAINT, version));
printStream.println();
}
}
希望通过本篇对于springboot启动方法的解读,让大家对springboot底层有了一个大致了解,只分析了主要方法,希望对大家有帮助
对于技术交流和探讨,或者想跳槽加薪的可以关注我的公众号,免费领取面试资料和技术书籍
本文地址:https://blog.csdn.net/weixin_44302240/article/details/110499108
推荐阅读
-
Java中启动线程start和run的两种方法
-
Intellij IDEA实现SpringBoot项目多端口启动的两种方法
-
Intellij IDEA实现SpringBoot项目多端口启动的两种方法
-
Android启动页广告(腾讯广告联盟)解决方法及源码下载
-
CloudStack SSVM启动条件源码阅读与问题解决方法
-
spring-boot-2.0.3不一样系列之源码篇 - run方法(三)之createApplicationContext,绝对有值得你看的地方
-
Android启动页广告(腾讯广告联盟)解决方法及源码下载
-
SpringBoot 源码解析 (三)----- Spring Boot 精髓:启动时初始化数据
-
SpringBoot 启动方法run()源码赏析
-
spring-boot-2.0.3不一样系列之源码篇 - SpringApplication的run方法(一)之SpringApplicationRunListener,绝对有值得你看的地方