12.SpringBoot启动配置原理
启动流程
1.启动类先创建SpringApplication对象
@SpringBootApplication @MapperScan({"com.example.demo.mapper"}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
public class SpringApplication { private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return (new SpringApplication(sources)).run(args); } public SpringApplication(Object... sources) { initialize(sources); } private void initialize(Object[] sources) { // 保存主配置类:判断是否为null,不为null保存再sources中 if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } // 判断当前应用是否是web应用 this.webEnvironment = deduceWebEnvironment(); // 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //从多个配置类中找到有main方法的主配置类 this.mainApplicationClass = deduceMainApplicationClass(); } // 判断当前应用是否是web应用 private boolean deduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return false; } } return true; } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } public void setInitializers( Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<ApplicationContextInitializer<?>>(); this.initializers.addAll(initializers); } public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<ApplicationListener<?>>(); this.listeners.addAll(listeners); } //从多个配置类中找到有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; } }
从类路径下找到META-INF/spring.factories
配置的所有ApplicationContextInitializer
然后保存起来
public abstract class SpringFactoriesLoader { public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } }
不光spring-boot-autoconfigure
依赖,其他依赖包内的META-INF/spring.factories
也都会加载。
从类路径下找到META-INF/spring.factories
配置的所有ApplicationListener
以上执行完成后,SpringApplicatioin 对象创建完成,接下来调 run()
方法。
2.再调用run方法
public class SpringApplication { public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); //获取SpringApplicationRunListeners 从类路径下META-INF/spring.factories SpringApplicationRunListeners listeners = getRunListeners(args); //回调所有的获取SpringApplicationRunListener.starting()方法 listeners.starting(); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 打印spring的图标在控制台 Banner printedBanner = printBanner(environment); //创建ApplicationContext决定创建web的ioc还是普通的ioc context = createApplicationContext(); analyzers = new FailureAnalyzers(context);//出现异常创建分析报告 //准备上下文环境 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新容器:进行ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat) //扫描、创建、加载所有组件的地方(配置类、组件、自动配置) refreshContext(context); //从IOC容器中获取所有的ApplicationRunner和CommandLineRunner进行回调 //ApplicationRunner先回调,CommandLineRunner再回调 afterRefresh(context, applicationArguments); //所有的SpringApplicationRunListener回调finished方法 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } //整个SpringBoot应用启动完成以后返回启动的ioc容器 return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } } //准备环境 private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment 创建或者配置环境 ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); //创建环境完成后回调SpringApplicationRunListener.environmentPrepared()表示环境准备完成 listeners.environmentPrepared(environment); //如果是web环境则转换成web环境 if (!this.webEnvironment) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } return environment; } public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework." + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext"; //创建ApplicationContext决定创建web的ioc还是普通的ioc protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { // 反射创建IOC容器 contextClass = Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); } //准备上下文环境 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //将environment保存到ioc中 context.setEnvironment(environment); postProcessApplicationContext(context);//注册一些组件 //回调之前保存的所有的ApplicationContextInitializer的initialize方法 applyInitializers(context); //回调所有的SpringApplicationRunListener的contextPrepared()方法 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded() listeners.contextLoaded(context); } protected void applyInitializers(ConfigurableApplicationContext context) { //获取创建SpringApplication对象时加载的所有Initializer //回调之前保存的所有的ApplicationContextInitializer的initialize方法 for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); //在环境准备好以后调用初始化器的initialize initializer.initialize(context); } } }
回调所有的SpringApplicationRunListener
的contextPrepared()
方法
class SpringApplicationRunListeners { public void contextPrepared(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextPrepared(context); } } public void contextLoaded(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); } } }
本文来自博客园,作者:Lz_蚂蚱,转载请注明原文链接:https://www.cnblogs.com/leizia/p/17208383.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2022-03-12 Linux安装JDK、MySQL、Redis、Tomcat
2022-03-12 网卡配置
2022-03-12 主机名配置