SpringBoot 啟動方法run()源碼解析
入口
通常一個簡單的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底層有瞭一個大致瞭解,隻分析瞭主要方法,希望對大傢有幫助
到此這篇關於SpringBoot 啟動方法run()源碼賞析的文章就介紹到這瞭,更多相關SpringBoot 啟動run()內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java SpringBoot核心源碼詳解
- SpringBoot詳解執行過程
- Springboot自動掃描包路徑來龍去脈示例詳解
- 教你怎麼用Springboot自定義Banner圖案
- Spring中Bean的加載與SpringBoot的初始化流程詳解