ToB企服应用市场:ToB评测及商务社交产业平台

标题: 给她讲最爱的SpringBoot源码 [打印本页]

作者: 立山    时间: 2022-11-3 15:11
标题: 给她讲最爱的SpringBoot源码
1 Spring boot源码环境构建

推荐环境:
idea:2020.3
gradle:版本gradle-6.5.1
jdk:1.8
注意!idea和gradle的版本有兼容性问题,要注意搭配
1.1 Spring boot源码下载

1、从github获取源码,网址:
  1. https://github.com/spring-projects/spring-boot
复制代码
我们要搭建的是2.4.3.RELEASE版本,所以点击release 之后在tags查找相应版本或者访问
  1. https://github.com/spring-projects/spring-boot/releases/tag/v2.4.3
复制代码
找到 后点击sourcecode下载源码压缩包

目录结构

Spring-boot-project 核心代码,代码量很多(197508 行)
Spring-boot-tests 测试代码
2、直接用提供的源码包(推荐)
将源码导入到idea。漫长的等待……

1.2 Spring boot源码编译

1、环境配置
推荐配置:

2、开始gradle构建
使用idea的build,不要用gradle的任务

看到下面的BUILE  SUCESSFUL表示成功

1.3 Spring boot冒烟测试

在springboot-boot-tests模块下很多冒烟测试的,会拖慢上面的编译,只留下了一个:
spring-boot-smoke-test-hibernate52工程来进行冒烟测试,打开Hibernate52Application.java文件,直接执行main方法启动springboot,成功!
org.springframework.boot.tests.hibernate52.Hibernate52Application
  1. package org.springframework.boot.tests.hibernate52;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class Hibernate52Application {
  6.         public static void main(String[] args) {
  7.                 SpringApplication.run(Hibernate52Application.class, args);
  8.         }
  9. }
复制代码
执行run
console中出现我们熟悉的图标。

2  Spring boot源码深度剖析
  1. 引言
  2. 使用过SpringBoot开发项目的读者应该都能够感觉到
  3. SpringBoot的开发完成后,只需要通过执行一个main方法就可以将整个web项目启动
  4. 无需将项目的jar文件放在tomcat下,然后启动tomcat,进而启动项目。
  5. 除此之外,好多依赖的jar包也无需我们再进行手动配置,减少了配置,
  6. 同时也减少了许多xml文件的配置,大大简化了我们的开发过程
  7. 那么
  8. springboot在启动的时候到底做了哪些事情?
复制代码
2.1 Spring boot启动流程剖析

第一步:new SpringApplication(primarySources)
第二步:run!
2.1.1  Spring boot启动流程剖析

Debug一下,追踪一下整个启动过程
main方法作为程序的入口,执行SpringApplication.run(),传入参数是启动类的class对象

1)Spring boot源码入口
  1. @SpringBootApplication
  2. public class Hibernate52Application {
  3.         public static void main(String[] args)  {
  4.                 SpringApplication.run(Hibernate52Application.class, args);
  5.         }
  6. }
复制代码
跟踪run方法;进入到
参数一可支持多个主要资源。
  1.         public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  2.                 return run(new Class<?>[] { primarySource }, args);
  3.         }
复制代码
继续进入到run方法
  1.         public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  2.                 return new SpringApplication(primarySources).run(args);
  3.         }
复制代码
2)构造器(new)
  1. //方法目标
  2. //1、初始化资源加载器(classloader)
  3. //2、处理primarySources
  4. //3、web应用类型推断 (web、reactive、servlet)
  5. //4、通过spring.factories加载配置类并初始化监听器 (SPI) 【重点】
  6. //5、提取主类
复制代码
  1.         public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2.                 //null;资源加载器,用来获取 Resource 和 classLoader 以及加载资源
  3.                 this.resourceLoader = resourceLoader;
  4.                 Assert.notNull(primarySources, "PrimarySources must not be null");
  5.                 //存放主加载类;set中可同时创建多个Application,最后要解析这个来源上的注解
  6.                 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  7.                 //推断 web 类型:servlet 或 reactive
  8.                 this.webApplicationType = WebApplicationType.deduceFromClasspath();
  9. //                0个,从spring.factories中找出Bootstrapper对应的属性
  10.                 this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
  11. //                7个,设置初始化器,从spring.factories中找出ApplicationContextInitializer对应的属性
  12.                 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  13. //                9个,设置监听器 从spring.factories中找出ApplicationListener对应的属性
  14.                 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  15.                 //找出主函数main的类
  16.                 this.mainApplicationClass = deduceMainApplicationClass();
  17.         }
复制代码
上面 的代码最终会调用到getSpringFactoriesInstances,从spring.factories加载属性配置
加载核心源码如下
下面代码
首先会用classLoader加载类路径下的所有spring.factories的配置内容,loadSpringFactories方法将返回一个key=接口名,value=实现类集合的Map结构
  1. private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
  2.     // 先试着取缓存
  3.                 Map<String, List<String>> result = cache.get(classLoader);
  4.                 if (result != null) {
  5.                         return result;
  6.                 }
  7.                 result = new HashMap<>();
  8.                 try {
  9.              // 获取所有spring.factories的URL(3个地方)
  10.                         Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
  11.             // 遍历URL
  12.                         while (urls.hasMoreElements()) {
  13.                                 URL url = urls.nextElement();
  14.                                 UrlResource resource = new UrlResource(url);
  15.                  // 加载每个URL中的properties配置
  16.                                 Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  17.            
  18.                                 for (Map.Entry<?, ?> entry : properties.entrySet()) {
  19.                     
  20.                                         String factoryTypeName = ((String) entry.getKey()).trim();
  21.                           // 将实现类的配置按照","符号分割开
  22.                                         String[] factoryImplementationNames =
  23.                                                         StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
  24.                                         for (String factoryImplementationName : factoryImplementationNames) {
  25.                              // 逐个添加到接口对应的集合当中
  26.                                                 result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
  27.                                                                 .add(factoryImplementationName.trim());
  28.                                         }
  29.                                 }
  30.                         }
  31.                         // Replace all lists with unmodifiable lists containing unique elements
  32.                         result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
  33.                                         .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
  34.             //加入缓存
  35.                         cache.put(classLoader, result);
  36.                 }
  37.                 catch (IOException ex) {
  38.                         throw new IllegalArgumentException("Unable to load factories from location [" +
  39.                                         FACTORIES_RESOURCE_LOCATION + "]", ex);
  40.                 }
  41.                 return result;
  42.         }
复制代码

主要的spring.factories
  1. spring-boot-2.4.3/spring-boot-project/spring-boot-autoconfigure/build/resources/main/META-INF/spring.factories
  2. spring-boot-2.4.3/spring-boot-project/spring-boot/build/resources/main/META-INF/spring.factories
  3. spring-beans-5.3.4.jar!/META-INF/spring.factories
复制代码
构造器流程总结
1、处理资源加载器、主要资源primarySources
2、web应用类型推断
3、从spring.factories中找出引导包装器、初始化器、监听器
4、设置应用程序主类
3)boot运行(run)

发布事件
打印banner
初始化ioc容器,启动tomcat
七大步骤
  1. //七大步骤
  2.         public ConfigurableApplicationContext run(String... args) {
  3.                 //计时器
  4.                 StopWatch stopWatch = new StopWatch();
  5.                 stopWatch.start(); //开始计时
  6.                 //  创建启动上下文对象
  7.                 DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  8.                 // 可配置的程序容器
  9.                 ConfigurableApplicationContext context = null;
  10.                 // 设置属性 不重要
  11.                 configureHeadlessProperty();
  12.                         // 第一步:获取并启动监听器    从spring.factories文件中加载【测试点】
  13.                 SpringApplicationRunListeners listeners = getRunListeners(args);
  14.                         //监听器发布ApplicationStartingEvent 事件.
  15.                 listeners.starting(bootstrapContext, this.mainApplicationClass);
  16.                 try {
  17.                         // 对参数进行包装(ApplicationArguments)
  18.                         ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  19.                         //第二步:准备应用程序环境【关键点】
  20.                         ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  21.                         // 配置忽略bean的信息(不重要)
  22.                         configureIgnoreBeanInfo(environment);
  23.                         //第三步: 打印banner(可自定义,参考讲义)【关键点】
  24.                         Banner printedBanner = printBanner(environment);
  25.             // 第四步:创建spring容器
  26.                         context = createApplicationContext();
  27.                         context.setApplicationStartup(this.applicationStartup);
  28.                         //第五步:准备 applicationContext
  29.                         prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  30.                         //第六步:ioc的refresh创建容器,初始化bean,tomcat也在这里被启动起来 【关键点】
  31.                         refreshContext(context);
  32.                         //第七步:上下文刷新后触发(空方法)
  33.                         afterRefresh(context, applicationArguments);
  34.                         stopWatch.stop();//停止计时
  35.                         if (this.logStartupInfo) {
  36.                                 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  37.                         }
  38.                         // 发布started事件
  39.                         listeners.started(context);
  40.                         //执行runner的run方法 【测试点】
  41.                         callRunners(context, applicationArguments);
  42.                 } catch (Throwable ex) {
  43.                         // 异常处理
  44.                         handleRunFailure(context, ex, listeners);
  45.                         throw new IllegalStateException(ex);
  46.                 }
  47.                 try {
  48.                         // 触发running事件
  49.                         listeners.running(context);
  50.                 } catch (Throwable ex) {
  51.                         handleRunFailure(context, ex, null);
  52.                         throw new IllegalStateException(ex);
  53.                 }
  54.                 // 返回最终构建的容器对象
  55.                 return context;
  56.         }
复制代码
2.1.2 Spring boot七大步骤详解

1)获取并启动监听器

这里的启动监听就是我们需要监听SpringBoot的启动流程监听,实现SpringApplicationRunListener类即可监听
  1.         //获取spring.factories中 key为SpringApplicationRunListener的对象实例。
  2.         private SpringApplicationRunListeners getRunListeners(String[] args) {
  3.                 Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
  4.                 // 通过从 spring.factories 中获取 SpringApplicationRunListener 类型的配置类
  5.                 return new SpringApplicationRunListeners(logger,
  6.                                 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
  7.                                 this.applicationStartup);
  8.         }
复制代码
查看具体SpringApplicationRunListener都有哪些方法
  1. package org.springframework.boot;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.ConfigurableApplicationContext;
  4. import org.springframework.core.env.ConfigurableEnvironment;
  5. import org.springframework.core.io.support.SpringFactoriesLoader;
  6. public interface SpringApplicationRunListener {
  7.         /**
  8.          * Called immediately when the run method has first started. Can be used for very
  9.          * early initialization.
  10.          * @param bootstrapContext the bootstrap context
  11.          */
  12.         //当调用run方法后会立即调用,可以用于非常早期的初始化
  13.         default void starting(ConfigurableBootstrapContext bootstrapContext) {
  14.                 starting();
  15.         }
  16.         /**
  17.          * Called immediately when the run method has first started. Can be used for very
  18.          * early initialization.
  19.          * @deprecated since 2.4.0 in favor of {@link #starting(ConfigurableBootstrapContext)}
  20.          */
  21.         @Deprecated
  22.         default void starting() {
  23.         }
  24.         /**
  25.          * Called once the environment has been prepared, but before the
  26.          * {@link ApplicationContext} has been created.
  27.          * @param bootstrapContext the bootstrap context
  28.          * @param environment the environment
  29.          */
  30.         //环境准备好之后调用
  31.         default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
  32.                         ConfigurableEnvironment environment) {
  33.                 environmentPrepared(environment);
  34.         }
  35.         /**
  36.          * Called once the environment has been prepared, but before the
  37.          * {@link ApplicationContext} has been created.
  38.          * @param environment the environment
  39.          * @deprecated since 2.4.0 in favor of
  40.          * {@link #environmentPrepared(ConfigurableBootstrapContext, ConfigurableEnvironment)}
  41.          */
  42.         @Deprecated
  43.         default void environmentPrepared(ConfigurableEnvironment environment) {
  44.         }
  45.         /**
  46.          * Called once the {@link ApplicationContext} has been created and prepared, but
  47.          * before sources have been loaded.
  48.          * @param context the application context
  49.          */
  50.         //在加载资源之前,ApplicationContex准备好之后调用
  51.         default void contextPrepared(ConfigurableApplicationContext context) {
  52.         }
  53.         /**
  54.          * Called once the application context has been loaded but before it has been
  55.          * refreshed.
  56.          * @param context the application context
  57.          */
  58.         //在加载应用程序上下文但在其刷新之前调用
  59.         default void contextLoaded(ConfigurableApplicationContext context) {
  60.         }
  61.         /**
  62.          * The context has been refreshed and the application has started but
  63.          * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
  64.          * ApplicationRunners} have not been called.
  65.          * @param context the application context.
  66.          * @since 2.0.0
  67.          */
  68.         /**
  69.          * 上下文已经刷新且应用程序已启动且所有{@link CommandLineRunner commandLineRunner}
  70.          * 和{@link ApplicationRunner ApplicationRunners}未调用之前调用
  71.          */
  72.         default void started(ConfigurableApplicationContext context) {
  73.         }
  74.         /**
  75.          * Called immediately before the run method finishes, when the application context has
  76.          * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
  77.          * {@link ApplicationRunner ApplicationRunners} have been called.
  78.          * @param context the application context.
  79.          * @since 2.0.0
  80.          */
  81.         /**
  82.          * 当应用程序上下文被刷新并且所有{@link CommandLineRunner commandLineRunner}
  83.          * 和{@link ApplicationRunner ApplicationRunners}都已被调用时,在run方法结束之前立即调用。
  84.          */
  85.         default void running(ConfigurableApplicationContext context) {
  86.         }
  87.         /**
  88.          * Called when a failure occurs when running the application.
  89.          * @param context the application context or {@code null} if a failure occurred before
  90.          * the context was created
  91.          * @param exception the failure
  92.          * @since 2.0.0
  93.          */
  94.         //在启动过程发生失败时调用
  95.         default void failed(ConfigurableApplicationContext context, Throwable exception) {
  96.         }
  97. }
复制代码
2)准备应用程序环境

创建并配置SpringBooty应用将要使用的Environment
  1. //不看细节,看返回的环境数据即可
  2.         //创建并配置SpringBooty应用将要使用的Environment
  3.         //过程如下:
  4.         //        1、创建配置环境 ConfigurableEnvironment
  5.         //        2、加载属性文件资源
  6.         //        3、配置监听
  7.         private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
  8.                                                                                                            DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
  9.                 // 根据不同的web类型创建不同实现的Environment对象
  10.                 ConfigurableEnvironment environment = getOrCreateEnvironment();
  11.                 // 配置环境
  12.                 configureEnvironment(environment, applicationArguments.getSourceArgs());
  13.                 ConfigurationPropertySources.attach(environment);
  14.                 // 发送环境已准备完成事件
  15.                 listeners.environmentPrepared(bootstrapContext, environment);
  16.                 DefaultPropertiesPropertySource.moveToEnd(environment);
  17.                 // 根据命令行参数中spring.profiles.active属性配置Environment对象中的activeProfile(比如dev、prod、test)
  18.                 configureAdditionalProfiles(environment);
  19.                 // 绑定环境中spring.main属性绑定到SpringApplication对象中
  20.                 bindToSpringApplication(environment);
  21.                 // 如果用户使用spring.main.web-application-type属性手动设置了webApplicationType
  22.                 if (!this.isCustomEnvironment) {
  23.                         // 将环境对象转换成用户设置的webApplicationType相关类型,他们是继承同一个父类,直接强转
  24.                         environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
  25.                                         deduceEnvironmentClass());
  26.                 }
  27.                 ConfigurationPropertySources.attach(environment);
  28.                 return environment; //环境查看(控制台)
  29.         }
复制代码
查看环境

3)控制台打印Banner
  1.         private Banner printBanner(ConfigurableEnvironment environment) {
  2.                 // banner模式,可以是console、log、off
  3.                 if (this.bannerMode == Banner.Mode.OFF) {
  4.                         return null;
  5.                 }
  6.                 ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
  7.                                 : new DefaultResourceLoader(null);
  8.                 SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
  9.                 //日志打印banner
  10.                 if (this.bannerMode == Mode.LOG) {
  11.                         return bannerPrinter.print(environment, this.mainApplicationClass, logger);
  12.                 }
  13.                 //控制台打印banner
  14.                 return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
  15.         }
复制代码
最终打印
通过org.springframework.boot.ResourceBanner#printBanner
  1.         @Override
  2.         public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
  3.                 try {
  4.                         String banner = StreamUtils.copyToString(this.resource.getInputStream(),
  5.                                         environment.getProperty("spring.banner.charset", Charset.class, StandardCharsets.UTF_8));
  6.                         for (PropertyResolver resolver : getPropertyResolvers(environment, sourceClass)) {
  7.                                 banner = resolver.resolvePlaceholders(banner);
  8.                         }
  9.                         out.println(banner);//此处打印
  10.                 }
  11.                 catch (Exception ex) {
  12.                         logger.warn(LogMessage.format("Banner not printable: %s (%s: '%s')", this.resource, ex.getClass(),
  13.                                         ex.getMessage()), ex);
  14.                 }
  15.         }
复制代码
截图如下

4)创建应用上下文对象
  1.         protected ConfigurableApplicationContext createApplicationContext() {
  2.                 return this.applicationContextFactory.create(this.webApplicationType);
  3.         }
复制代码
调用到下面
  1. public interface ApplicationContextFactory {
  2.         /**
  3.          * A default {@link ApplicationContextFactory} implementation that will create an
  4.          * appropriate context for the {@link WebApplicationType}.
  5.          */
  6.         //返回一个应用程序上下文
  7.         ApplicationContextFactory DEFAULT = (webApplicationType) -> {
  8.                 try {
  9.                         switch (webApplicationType) {
  10.                         case SERVLET:
  11.                                 return new AnnotationConfigServletWebServerApplicationContext();
  12.                         case REACTIVE:
  13.                                 return new AnnotationConfigReactiveWebServerApplicationContext();
  14.                         default:
  15.                                 return new AnnotationConfigApplicationContext();
  16.                         }
  17.                 }
  18.                 catch (Exception ex) {
  19.                         throw new IllegalStateException("Unable create a default ApplicationContext instance, "
  20.                                         + "you may need a custom ApplicationContextFactory", ex);
  21.                 }
  22.         };
复制代码
5)准备应用上下文

核心代码如下
  1.         /**
  2.          * Spring容器准备
  3.          */
  4.         private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
  5.                                                                 ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
  6.                                                                 ApplicationArguments applicationArguments, Banner printedBanner) {
  7.                 context.setEnvironment(environment);//设置环境
  8.                 postProcessApplicationContext(context);//设置上下文
  9.                 // 执行所有ApplicationContextInitializer对象的initialize方法(这些对象是通过读取spring.factories加载)
  10.                 applyInitializers(context);//设置初始化工作(不用看)
  11.                 // 发布上下文准备完成事件到所有监听器
  12.                 listeners.contextPrepared(context);//触发监听器
  13.                 bootstrapContext.close(context);
  14.                 if (this.logStartupInfo) { //日志操作
  15.                         logStartupInfo(context.getParent() == null);
  16.                         logStartupProfileInfo(context);
  17.                 }
  18.                 // 获取工厂 DefaultListableBeanFactory
  19.                 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  20.                 //注册单例对象
  21.                 beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  22.                 if (printedBanner != null) {
  23.                         //注册banner单例对象
  24.                         beanFactory.registerSingleton("springBootBanner", printedBanner);
  25.                 }
  26.                 if (beanFactory instanceof DefaultListableBeanFactory) {
  27.                         //是否覆盖bean
  28.                         ((DefaultListableBeanFactory) beanFactory)
  29.                                         .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  30.                 }
  31.                 if (this.lazyInitialization) { //是否懒加载
  32.                         context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  33.                 }
  34.                 // Load the sources
  35.                 Set<Object> sources = getAllSources();
  36.                 Assert.notEmpty(sources, "Sources must not be empty");
  37.                 //加载(业务类的注解需要扫描)  bean到上下文
  38.                 load(context, sources.toArray(new Object[0]));
  39.                 // 发送上下文加载完成事件
  40.                 listeners.contextLoaded(context);
  41.         }
复制代码
6)刷新应用程序上下文

ioc容器初始化
重要!
tomcat的启动在这里!
  1.   //核心方法
  2.         private void refreshContext(ConfigurableApplicationContext context) {
  3.                 // ……
  4.                 // 开始执行启动容器(调用模板方法)
  5.                 refresh((ApplicationContext) context);
  6.         }
复制代码
扩展问题:
如果在springboot里使用了web容器,它是如何启动的?
refreshContext 里面,沿着 refresh - onRefresh,注意是 ServletWebServerApplicationContext的
我们说,在普通的spring里onRefresh是个空方法,留给子类去实现,那么,
看看这个 ServletWebServerApplicationContext 实现类它的 onRefresh偷偷干了些啥见不得人的事?……
7)容器回调方法

空方法
  1.         protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
  2.         }
复制代码
run方法启动后
主要做如下几件事情:
1、发出启动结束事件
2、执行实现ApplicationRunner、CommandLineRunner的run方法
3、发布应用程序已启动(ApplicationStartedEvent)事件
4、异常处理
小疑问:
boot启动了一个web,那么一定有一个DispacherServlet,它是啥时候被加载的呢???
提示:
@EnableAutoConfiguration 注解的spi,在spring-boot-autoconfigure的spring.factories里
EnableAutoConfiguration的加载类里有个:DispatcherServletAutoConfiguration 做了自动装配
秘密就藏在这货里
那自动装配又是什么鬼呢?除了DS,还有各种starter,怎么加载的呢?下节课继续……
2.2 boot自定义Banner

banner自动生成工具,ascii文字展示
  1. http://www.network-science.de/ascii/
复制代码

Spring boot启动如下

在路径
  1. \spring-boot-tests\spring-boot-smoke-tests\spring-boot-smoke-test-hibernate52\src\main\resources
复制代码
下创建banner.txt(注意:文件名称不能变,否则无法加载)
banner.txt内容如下
  1. 88b           d88             88888888ba                                 
  2. 888b         d888             88      "8b                          ,d     
  3. 88`8b       d8'88             88      ,8P                          88     
  4. 88 `8b     d8' 88 8b       d8 88aaaaaa8P'  ,adPPYba,   ,adPPYba, MM88MMM  
  5. 88  `8b   d8'  88 `8b     d8' 88""""""8b, a8"     "8a a8"     "8a  88     
  6. 88   `8b d8'   88  `8b   d8'  88      `8b 8b       d8 8b       d8  88     
  7. 88    `888'    88   `8b,d8'   88      a8P "8a,   ,a8" "8a,   ,a8"  88,   
  8. 88     `8'     88     Y88'    88888888P"   `"YbbdP"'   `"YbbdP"'   "Y888  
  9.                       d8'                                                
  10.                      d8'                                               
复制代码
2.3 面试题

1、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
​      组合了
  1. @AutoConfigurationPackage
  2. @Import(AutoConfigurationImportSelector.class)
复制代码
2、Spring Boot 自动配置原理是什么?
注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,
@EnableAutoConfiguration 给容器导入META-INF/spring.factories 里定义的自动配置类。
筛选有效的自动配置类。
每一个自动配置类结合对应的 xxx.java 读取配置文件进行自动配置功能
3、Spring Boot 中的 starter 到底是什么 ?
首先,这个 Starter 并非什么新的技术点,基本上还是基于 Spring 已有功能来实现的。首先它提供了一个自动化配置类,一般命名为 XXXAutoConfiguration ,在这个配置类中通过条件注解来决定一个配置是否生效(条件注解就是 Spring 中原本就有的),然后它还会提供一系列的默认配置,也允许开发者根据实际情况自定义相关配置,然后通过类型安全的属性注入将这些配置属性注入进来,新注入的属性会代替掉默认属性。正因为如此,很多第三方框架,我们只需要引入依赖就可以直接使用了。当然,开发者也可以自定义 Starter
4、运行 Spring Boot 有哪几种方式?
1)打包用命令或者放到容器中运行
2)用 Maven/ Gradle 插件运行
3)直接执行 main 方法运行
本文由传智教育博学谷教研团队发布。
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。
转载请注明出处!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4