Springboot核心功能:高级特性、原理解析

文章目录

Profile功能

为了方便多环境适配,springboot简化了profile功能。

比如,生产环境、测试环境各自有各自的配置文件,切换不同环境时只要告诉springboot切换到哪个配置文件即可。

1. application-profile功能

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

  • 指定环境配置文件: application-{env}.yaml

    • -后的名字任取,例如:application-prod.yaml 生产环境
  • 激活指定环境方式:

    1. 配置文件激活

      spring:
        profiles:
          active: ... # 只需写 - 后的名称,如application-prod.yaml => prod。
      
    2. 命令行激活:
      java -jar xxx.jar --spring.profiles.active=prod --person.name=haha

      修改配置文件的任意值,命令行优先

  • 规则:

    • 默认配置与环境配置同时生效
    • 同名配置项,profile配置优先

2. @Profile条件装配功能

@Configuration(proxyBeanMethods = false)
@Profile("production") //此时此类 当环境为 production时才生效
public class ProductionConfiguration {

    // ...

}

3. profile分组

========================application配置文件============================================
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq

# 使用:--spring.profiles.active=production  激活
spring.profiles.active=production

外部化配置

外部化配置:将代码中的配置信息绑定到外部文件中就称为外部化配置。

springboot官方说明了外部化配置的规则:

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 annotations on your @Configuration classes. Please note that such property sources are not added to the Environment 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 and the test annotations for testing a particular slice of your application.
  13. @TestPropertySource annotations on your tests.
  14. Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.
  1. 外部配置源(springboot可查找外部配置的位置)

    • 常用:Java属性文件(.properties文件)、YAML文件(.yaml)、环境变量命令行参数

    比如使用@Value注解

    @Value("${person.name}") //可以获取配置文件的值
    @Value("${JAVA_HOME}") //也可以获取环境变量的值
    @Value("${os.name}") //也可以获取操作系统的名字
    
  2. 配置文件查找位置:(优先级:后面的会覆盖前面的)

    1. classpath 根路径

    2. classpath 根路径下config目录

    3. jar包当前目录

    4. jar包当前目录的config目录

    5. /config子目录的直接子目录

  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. 指定环境优先,外部优先(后面的可以覆盖前面的同名配置项)

自定义starter

1. 自定义starter启动原理

  1. starter的pom文件中引入 autoconfigurer 包

    Springboot核心功能:高级特性、原理解析
  2. autoconfigure包中配置使用 META-INF/spring.factoriesEnableAutoConfiguration 的值,使得项目启动加载指定的自动配置类(这是核心,springboot启动时会扫描指定路径下的类)

  3. 编写自动配置类 xxxAutoConfiguration -> xxxxProperties

    1. @Configuration
    • @Conditional
    • @EnableConfigurationProperties
    • @Bean

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

2. 自定义starter示例

举例:

  1. 建两个项目
    1. atguigu-hello-spring-boot-starter(启动器): maven模块

      1. pom文件中加:自动配置包的maven依赖

        <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
        
            <groupId>com.atguigu</groupId>
            <artifactId>atguigu-hello-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        
            <dependencies>
                <dependency>
                    <groupId>com.atguigu</groupId>
                    <artifactId>atguigu-hello-spring-boot-starter-autoconfigure</artifactId>
                    <version>0.0.1-SNAPSHOT</version>
                </dependency>
            </dependencies>
        
        </project>
        
      2. 打包

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jf5l5j0G-1627625678765)(D:\笔记\typroa_images\image-20210612144740138.png)]

    2. atguigu-hello-spring-boot-starter-autoconfigure(自动配置包): springboot模块

      1. 此项目不单独打包使用。所以test包、主程序类、配置类都可以删掉。

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kIglfYD8-1627625678767)(D:\笔记\typroa_images\image-20210612142543084.png)]

      2. pom文件如下:

        <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
            <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.4.6</version>
                <relativePath/> <!-- lookup parent from repository -->
            </parent>
            <groupId>com.atguigu</groupId>
            <artifactId>atguigu-hello-spring-boot-starter-autoconfigure</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <name>atguigu-hello-spring-boot-starter-autoconfigure</name>
            <description>Demo project for Spring Boot</description>
            <properties>
                <java.version>1.8</java.version>
            </properties>
        
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </dependency>
            </dependencies>
        </project>
        
        
      3. 写业务逻辑组件

        /**
         * 默认不要放在容器中
         */
        public class HelloService {
        
            @Autowired
            private HelloProperties helloProperties;
        
            public String sayHello(String userName) {
                return helloProperties.getPrefix() + ": " + userName + "》" + helloProperties.getSuffix();
            }
        }
        
        @ConfigurationProperties("atguigu.hello") //绑定配置文件
        public class HelloProperties {
        
            private String prefix;
            private String suffix;
        
            public String getPrefix() {
                return prefix;
            }
        
            public void setPrefix(String prefix) {
                this.prefix = prefix;
            }
        
            public String getSuffix() {
                return suffix;
            }
        
            public void setSuffix(String suffix) {
                this.suffix = suffix;
            }
        }
        
      4. 写自动配置类

        @Configuration
        @EnableConfigurationProperties(HelloProperties.class) //开启属性文件绑定功能,并将该组件HelloProperties放在容器中
        public class HelloServiceAutoConfiguration {
        
            @ConditionalOnMissingBean(HelloService.class)
            @Bean
            public HelloService helloService() {
                HelloService helloService = new HelloService();
                return helloService;
            }
        }
        
      5. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzJ47j79-1627625678768)(D:\笔记\typroa_images\image-20210612143818051.png)]

      6. 配置使用 META-INF/spring.factories 中 EnableAutoConfiguration 的值,使得项目启动加载指定的自动配置类
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XEEoDoZ4-1627625678770)(D:\笔记\typroa_images\image-20210612150620104.png)]

        #Auto Configure
        org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        hello.auto.HelloServiceAutoConfiguration
        
      7. 然后打包,供启动器使用。

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zV0gAbYx-1627625678771)(D:\笔记\typroa_images\image-20210612144623573.png)]

然后别的项目就可以导入maven依赖使用该启动器了。

步骤:

  1. 引入

    <dependencies>
    	<dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>atguigu-hello-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
    	</dependency>
    </dependencies>
    
  2. 测试:

    @RestController
    public class HelloContoller {
    
        @Autowired
        HelloService helloService; 
    
        @GetMapping("/hello")
        public String hello() {
            return helloService.sayHello("小明");
        }
    }
    

    配置文件:

    atguigu.hello.prefix=ATGUIGU
    atguigu.hello.suffix=你好
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UurI8vda-1627625678772)(D:\笔记\typroa_images\image-20210612153724597.png)]

SpringBoot原理

Spring原理【Spring注解】、SpringMVC原理、自动配置原理、SpringBoot原理

1. SpringBoot启动过程

public static void main(String[] args) {
    SpringApplication.run(XXXX.class, args);
}
  1. 创建 SpringApplication

    ============================SpringApplication===================================
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        	、、、
    	this.resourceLoader = resourceLoader;
    	Assert.notNull(primarySources, "PrimarySources must not be null");
    	this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));//保存一些信息。
    	this.webApplicationType = WebApplicationType.deduceFromClasspath();//判定当前应用的类型。
    	this.bootstrapRegistryInitializers = 		this.getBootstrapRegistryInitializersFromSpringFactories();
            this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
            this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = this.deduceMainApplicationClass();
    }
    
    1. 保存一些信息。

    2. 判定当前应用的类型(工具类:ClassUtils)。类型例如:Servlet

    3. bootstrapRegistryInitializers:初始启动引导器(说明了项目一启动要干什么)(List

      • 怎么找:去spring.factories文件中找org.springframework.boot.Bootstrapper
    4. ApplicationContextInitializer

      • spring.factoriesApplicationContextInitializer
      1. List<ApplicationContextInitializer<?>> initializers
    5. ApplicationListener ;应用监听器。

      • spring.factories找** ApplicationListener
      1. List<ApplicationListener<?>> listeners
  2. 运行 SpringApplication

    ============================SpringApplication===================================
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();//StopWatch
        stopWatch.start();//记录应用的启动时间
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();//创建引导上下文(Context环境)
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();//让当前应用进入headless模式。
        SpringApplicationRunListeners listeners = this.getRunListeners(args);//获取所有RunListener(运行监听器)
        listeners.starting(bootstrapContext, this.mainApplicationClass);
    
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //保存命令行参数
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);//准备环境
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();//创建IOC容器
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);//准备ApplicationContext IOC容器的基本信息
            this.refreshContext(context);//刷新IOC容器
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
    
            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }
    
        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
    
    1. StopWatch

    2. 记录应用的启动时间

    3. 创建引导上下文(Context环境)createBootstrapContext()

      1. 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
      public interface Bootstrapper {
      
          /**
           * Initialize the given {@link BootstrapRegistry} with any required registrations.
           * @param registry the registry to initialize
           */
          void intitialize(BootstrapRegistry registry);
      
      }
      
    4. 让当前应用进入headless模式。java.awt.headless

    5. 获取所有** RunListener**(运行监听器)【为了方便所有Listener进行事件感知】

      1. getSpringFactoriesInstances方法 去spring.factoriesSpringApplicationRunListener.

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-byq6KuBo-1627625678773)(D:\笔记\typroa_images\1607004823889-8373cea4-6305-40c1-af3b-921b071a28a8.png)]

      1. 遍历 SpringApplicationRunListener 调用 starting 方法;
      2. 以上步骤 相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
    6. 保存命令行参数;ApplicationArguments

    7. 准备环境 (prepareEnvironment();)

      1. 返回或者创建基础环境信息对象。StandardServletEnvironment

      2. 配置环境信息对象。

        1. 读取所有的配置源的配置属性值。
      3. 绑定环境信息

        1. 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
    8. 创建IOC容器(createApplicationContext())

      1. 根据当前项目类型(当前为Servlet)创建容器,
        1. 当前会创建 AnnotationConfigServletWebServerApplicationContext
    9. 准备ApplicationContext IOC容器的基本信息 prepareContext()

      1. 保存环境信息

      2. IOC容器的后置处理流程。

      3. 应用初始化器;applyInitializers;

        1. 遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能

          [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pi9Murnb-1627625678774)(D:\笔记\typroa_images\1607005958877-bf152e3e-4d2d-42b6-a08c-ceef9870f3b6.png)]

        2. 遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared

      4. 所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;

    10. **刷新IOC容器。**refreshContext

      1. 创建容器中的所有组件(Spring注解)
    11. 容器刷新完成后工作?afterRefresh

      1. 所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
      2. 调用所有runners;callRunners()
        1. 获取容器中的 ApplicationRunner
        2. 获取容器中的 CommandLineRunner
        3. 合并所有runner并且按照@Order进行排序
        4. 遍历所有的runner。调用 run 方法
    12. 如果以上有异常,

      1. 调用Listener 的 failed方法
    13. 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running

    14. **running如果有问题。继续通知 failed 。**调用所有 Listener 的 **failed;**通知所有的监听器 failed

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D8BAGhE9-1627625678775)(D:\笔记\typroa_images\1607006112013-6ed5c0a0-3e02-4bf1-bdb7-423e0a0b3f3c.png)]

@FunctionalInterface
public interface ApplicationRunner {

    /**
     * Callback used to run the bean.
     * @param args incoming application arguments
     * @throws Exception on error
     */
    void run(ApplicationArguments args) throws Exception;

}
@FunctionalInterface
public interface CommandLineRunner {

    /**
     * Callback used to run the bean.
     * @param args incoming main method arguments
     * @throws Exception on error
     */
    void run(String... args) throws Exception;

}

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

  • ApplicationRunner 与 CommandLineRunner

e CommandLineRunner {

/**
 * Callback used to run the bean.
 * @param args incoming main method arguments
 * @throws Exception on error
 */
void run(String... args) throws Exception;

}






## 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**



- ApplicationRunner 与 CommandLineRunner






上一篇:Spring Boot 自定义starter启动器


下一篇:如何编写一个自定义的SpringBoot-starter组件