1、Profile功能

为了方便多环境适配,springboot简化了profile功能。
开发环境—本地配置,生产环境—线上的各个服务配置

1、application-profile功能

  • 默认配置文件 application.yaml;任何时候都会加载

image.png

  • 指定环境配置文件 application-{env}.yaml
  • 默认配置与环境配置同时生效
  • 同名配置项,profile配置优先 命令行>指定配置文件>默认配置文件
  • 激活指定环境
    • 配置文件激活
    • 命令行激活:java -jar xxx.jar —spring.profiles.active=prod —person.name=haha 激活某个环境,并且修改某个配置的值
      • 修改配置文件的任意值,命令行优先

2、@Profile条件装配功能

指定注入数据是哪个环境的
image.png

  1. @Configuration(proxyBeanMethods = false) // 指定配置类中内容是哪个环境的
  2. @Profile("production")
  3. public class ProductionConfiguration {
  4. // ...
  5. }

3、profile分组

image.png

  1. 在一个新的配置文件中指定多个配置文件同时生效,形成互补
  2. // 这是一组
  3. spring.profiles.group.production[0]=proddb
  4. spring.profiles.group.production[1]=prodmq
  5. // 这是一组
  6. spring.profiles.group.mytest[0]=test
  7. 使用:--spring.profiles.active=production(组名) 激活

2、外部化配置

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
后面的可以覆盖前面的配置

  1. Default properties (specified by setting SpringApplication.setDefaultProperties).
  2. [@PropertySource](https://docs.spring.io/spring/docs/5.3.1/javadoc-api/org/springframework/context/annotation/PropertySource.html) annotations on your @Configuration classes. Please note that such property sources are not added to the Environment(环境变量,也可以通过Value获取环境变量) until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.
  3. Config data (such as **application.properties** files)
  4. A RandomValuePropertySource that has properties only in random.*.
  5. OS environment variables.
  6. Java System properties (System.getProperties()).
  7. JNDI attributes from java:comp/env.
  8. ServletContext init parameters.
  9. ServletConfig init parameters.
  10. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
  11. Command line arguments.
  12. properties attribute on your tests. Available on [@SpringBootTest](https://docs.spring.io/spring-boot/docs/2.4.0/api/org/springframework/boot/test/context/SpringBootTest.html) and the test annotations for testing a particular slice of your application.
  13. [@TestPropertySource](https://docs.spring.io/spring/docs/5.3.1/javadoc-api/org/springframework/test/context/TestPropertySource.html) annotations on your tests.
  14. Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.

1、外部配置源

常用:Java属性文件YAML文件环境变量命令行参数
获取各种环境变量
image.png
image.png

2、配置文件(YAML、Properties)查找位置

后面的可以覆盖前面的同名配置项
(1) classpath 根路径(项目resources下)
(2) classpath 根路径下config目录
(3) jar包当前目录(例如到云服务器/home目录发布一个jar包,那这个jar包能拿到/home目录下的配置文件)
(4) jar包当前目录的config目录
(5) /config子目录的直接子目录(好处:可以不修改老前辈的配置文件,只能是Linux)

3、配置文件加载顺序:

后面的可以覆盖前面的同名配置项

  1. 当前jar包内部的application.properties和application.yml
  2. 当前jar包内部的application-{profile}.properties 和 application-{profile}.yml
  3. 引用的外部jar包的application.properties和application.yml
  4. 引用的外部jar包的application-{profile}.properties 和 application-{profile}.yml

4、指定环境优先,外部优先,后面的可以覆盖前面的同名配置项

3、自定义starter

1、starter启动原理

  • starter-pom引入 autoconfigurer 包

image.png

  • autoconfigure包中配置使用 META-INF/spring.factoriesEnableAutoConfiguration 的值,使得项目启动加载指定的自动配置类
  • 编写自动配置类 xxxAutoConfiguration -> xxxxProperties

引入starter —- xxxAutoConfiguration —- 容器中放入组件 —— 绑定xxxProperties —— 配置项

2、自定义starter

  1. 创建空项目
  2. 创建并添加atguigu-hello-spring-boot-starter(启动器)

利用Maven场景启动器创建
image.png

  1. 创建并添加atguigu-hello-spring-boot-starter-autoconfigure(自动配置包)

利用spring boot场景启动器创建
image.png

  1. 引入atguigu-hello-spring-boot-starter-autoconfigure(自动配置包)

image.png

  1. 编写atguigu-hello-spring-boot-starter-autoconfigure(自动配置包)

    4、SpringBoot原理

    主要内容:
    Spring原理【Spring注解】、SpringMVC原理、自动配置原理、SpringBoot原理

1、SpringBoot启动过程

  • 创建 SpringApplication
    • 保存一些信息。
    • 判定当前应用的类型。利用ClassUtils类判断。如Servlet类型
      • 根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是什么应用类型,为后面创建什么样的IOC容器提供数据依据。
    • 遍历查找需要的 bootstrappers:初始启动引导器(List):去spring.factories文件中找 org.springframework.boot.Bootstrapper
    • 遍历查找需要的 ApplicationContextInitializer;去spring.factories找 ApplicationContextInitializer
      • List> initializers
    • 找 ApplicationListener ;应用监听器(监听状态)。spring.factories找 ApplicationListener
      • List> listeners
  • 运行 SpringApplication
    • StopWatch 监听整个应用程序启动停止的监听器
    • 记录应用的启动时间(用StopWatch)
    • 创建引导上下文(Context环境)createBootstrapContext()
      • 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
    • 让当前应用进入headless模式。java.awt.headless 简言之就是自力更生模式
    • 获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】
      • getSpringFactoriesInstances 去spring.factories找 SpringApplicationRunListener.
    • 遍历 SpringApplicationRunListener 调用 starting 方法;
      • 相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
    • 保存命令行参数;ApplicationArguments
      • java -jar xx.jar —server.port=8888 server.prot=8888就会存入ApplicationArguments中
    • 准备环境 prepareEnvironment();
      • 返回或者创建基础环境信息对象。StandardServletEnvironment
      • 配置环境信息对象。
        • 读取所有的配置源的配置属性值。
      • 绑定环境信息
      • 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
    • 创建IOC容器(createApplicationContext())
      • 根据项目类型(Servlet)创建容器,
      • 当前会创建 AnnotationConfigServletWebServerApplicationContext
        • 根据this.webApplicationType判断创建哪一个类型的容器在new SpringApplication方法中,this.webApplicationType可能为Reactive响应式应用;Servlet应用;None都不是
    • 准备ApplicationContext IOC容器的基本信息 prepareContext()
      • 保存环境信息
      • IOC容器的后置处理流程。
      • 应用初始化器;applyInitializers;
        • 遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能
        • 遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared
      • 所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;
    • 刷新IOC容器。refreshContext
      • 创建容器中的所有组件(Spring注解)
      • spring的核心方法

实际调用的是抽象类ApplicationContext.refresh()方法
该方法是一种模版方法的设计模式,定义了方法的执行顺序和骨架,其中onRefresh()是一个抽象方法,由具体子类实现.
因为启动的是web版的容器
因此执行的是ServletWebServerApplicationContext.refresh()方法
该方法从容器中获得一个ServletWebServerFactory工厂(如果有多个工厂,则抛异常)
根据工厂对象获得webServer对象
因为内嵌tomcat,所以是TomcatWevServer
后续通过new Tomcat()并执行start()启动tomcat服务器.

  • 容器刷新完成后工作(afterRefresh)为下面的内容
  • 所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
  • 调用所有runners;callRunners()
    • 获取容器中的 ApplicationRunner
    • 获取容器中的 CommandLineRunner
    • 合并所有runner并且按照@Order进行排序
    • 遍历所有的runner。调用 run 方法
  • 如果以上有异常,
    • 调用Listener 的 failed
  • 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running 了
    • running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed
  1. public interface Bootstrapper {
  2. /**
  3. * Initialize the given {@link BootstrapRegistry} with any required registrations.
  4. * @param registry the registry to initialize
  5. */
  6. void intitialize(BootstrapRegistry registry);
  7. }

image.png
image.png

image.png

  1. @FunctionalInterface
  2. public interface ApplicationRunner {
  3. /**
  4. * Callback used to run the bean.
  5. * @param args incoming application arguments
  6. * @throws Exception on error
  7. */
  8. void run(ApplicationArguments args) throws Exception;
  9. }
  1. @FunctionalInterface
  2. public interface CommandLineRunner {
  3. /**
  4. * Callback used to run the bean.
  5. * @param args incoming main method arguments
  6. * @throws Exception on error
  7. */
  8. void run(String... args) throws Exception;
  9. }

2、Application Events and Listeners

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners
ApplicationContextInitializer
ApplicationListener
SpringApplicationRunListener
**

3、ApplicationRunner 与 CommandLineRunner