SpringBoot 教程核心功能-原理解析

1.Profile 功能

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

1.1 application-profile 功能

  • 默认配置文件 application.yml 任何时候都会加载。
  • 指定环境配置文件 application-{env}.yml,env 通常替代为 test
  • 激活指定环境
  • 配置文件激活 : 在默认配置文件中配置  spring.profiles.active=test
  • 命令行激活 : java -jar xxx.jar --spring.profiles.active=test  (命令行与配置项相同,命令行优先)
  • 默认配置与环境配置同时生效
  • 同名配置项,profile 配置优先

application.properties

persion.name=张三1

#指定激活的环境。默认配置文件和指定环境的配置文件都会生效。
spring.profiles.active=test

application-prod.yml

person:
  name: prod-张三

application-test.yml 

person:
  name: test-张三

controller

@RestController
public class HelloController {
    @Value("${person.name:李四}")
    private String name;

    @GetMapping("/")
    public String hello() {
        return "hello "+name;
    }
}

当application.properties 指定【spring.profiles.active】为 test 时,输出【hello test-张三】;指定【spring.profiles.active】为 prod 时,输出【hello prod-张三】。

1.2 @Profile 条件装配功能

指定组件在哪个环境下才能被注册到容器中,不指定,任何环境下都能注册这个组件.

  1. 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,默认是default环境
  2. 卸载配置类上,只有是指定的环境的时候,整个配置类里面的所有的配置才会生效,有点类似@Conditional
  3. 没有标注环境标识的bean在任何环境下都是加载的

例1

如下三个entity

public class Human {
}

@Profile("prod")
@Data
@Component
public class Boss extends Human {
}

@Profile("test")
@Data
@Component
public class Worker extends Human {
}

controller

@RestController
public class HelloController {
    @Autowired
    Human human;

    @GetMapping("/human")
    public String human() {
        return human.getClass().toString();
    }
}

application.properties 指定【spring.profiles.active】为 test 时,输出【class com.cj.study.annoPro.Worker】

application.properties 指定【spring.profiles.active】为 prod 时,输出【class com.cj.study.annoPro.Boss】。

例2

@Configuration
public class MyConfig {
    @Profile("prod") //当激活 prod 时,Spring 容器中注入id为red的Color组件
    @Bean
    public Color red(){
        return new Color();
    }

    @Profile("test") //当激活 prod 时,Spring 容器中注入id为green的Color组件
    @Bean
    public Color green(){
        return new Color();
    }
}

1.3 profile 分组

 application-prod-extra.yml

person:
  age: 21

application-prod.yml

person:
  name: prod-张三

application-test.yml 

person:
  name: test-张三

application.properties

#当使用 profile 组时,激活内容为组名
spring.profiles.active=myProd

spring.profiles.group.myProd[0]=prod
spring.profiles.group.myProd[1]=prod-extra

spring.profiles.group.myTest[0]=test

Java 类

@Data
@Component
@ConfigurationProperties("person")
public class Person {
    private String name;
    private Integer age;
}


@RestController
public class HelloController {
    @Autowired
    Person person;

    @GetMapping("/")
    public Person hello() {
        return person;
    }
}

输出结果:

application.properties 指定【spring.profiles.active】为 myProd 时,输出【{"name":"prod-张三","age":21}】

application.properties 指定【spring.profiles.active】为 myTest 时,输出【{"name":"test-张三","age":8}】。

2.外部化配置

官方描述

  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-14,低级别优先级的同名配置项会被高级别的覆盖

外部配置源有如下几种:

  • Java 属性文件
  • yml 文件
  • 系统环境变量
@SpringBootApplication
public class Boot09ProfileApplication {
    //启动类可以获取系统的环境变量和系统的属性,这些值可以使用 @Value("{}") 来获取
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Boot09ProfileApplication.class, args);
        ConfigurableEnvironment environment = run.getEnvironment();
        Map<String,Object> sysEnvironment = environment.getSystemEnvironment(); //获取系统的环境变量
        Map<String,Object> propertiesEnvironment = environment.getSystemProperties(); //获取系统的属性
        
        System.out.println("------------系统的环境变量------------");
        for (Map.Entry<String,Object> entry : sysEnvironment.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
        System.out.println("------------系统的属性------------");
        for (Map.Entry<String,Object> entry : propertiesEnvironment.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }

}
  • 命令行参数   java -jar xxx.jar --spring.name=xxx

SpringBoot 查找配置文件的位置(优先级高的覆盖优先级低的同名配置):

  1. classpath 根路径
  2. classpath 根路径下 config 目录
  3. jar 包当前目录(应用打包好的jar包)
  4. jar 当前目录的 config 目录(应用打包好的jar包)
  5. /config 子目录的直接子目录(/config 下的一级目录) (windows 下测试:5不会覆盖4的同名配置项

配置文件的加载顺序

  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

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

3.自定义 starter

3.1 starter 启动原理

1、starter 的pom 文件需引入 autoconfigure 的依赖

 2、autoconfigure 包中配置 META/spring.factories 中 EnableAutoConfiguration,使得项目启动加载指定的自动配置类。

3、编写自动配置类 xxxxAutoConfiguration --> xxxProperties

@Configuration
@ConditionalOnMissingBean(Xxx.class)
@EnableConfigurationProperties(XxxProperties.class)//默认HelloProperties放在容器中
public class XxxAutoConfiguration {

    @Bean
    public Xxx xxx(){
        return new Xxx ();
    }

}

4、引入 starter -- xxxxAutoConfiguration -- 容器中放入组件 -- 绑定 xxxProperties -- 配置项

3.2 自定义 starter

项目 :boot-09-custom-starter

创建一个 empty project,命名为【boot-09-custom-starter】

项目 :hello-spring-boot-starter

在 【boot-09-custom-starter】 添加模块 【hello-spring-boot-starter】,【hello-spring-boot-starter】为普通 maven 工程

在 pom 文件引入 hello-spring-boot-starter-autoconfigure 依赖(即我们自定义的 autoconfiguration)。

    <dependencies>
        <dependency>
            <groupId>org.cj.hello</groupId>
            <artifactId>hello-spring-boot-starter-autoconfigure</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

项目 :hello-spring-boot-starter-autoconfigure

在 【boot-09-custom-starter】 添加模块 【hello-spring-boot-starter-autoconfigure】,【hello-spring-boot-starter-autoconfigure】为 SpringBoot 工程。(也可以创建普通 maven 工程,再手动添加 SpringBoot 的依赖项)。

在 pom 文件引入 spring-boot-starter 依赖(即我们自定义的 autoconfiguration)。

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

绑定的属性类

@Data
@ConfigurationProperties("hello")
public class HelloProperties {
    private String prefix;
    private String suffix;
}

HelloService 类

/**
 * 默认不要放到容器中,通过自动导入
 */
public class HelloService {
    @Autowired
    HelloProperties helloProperties;

    public String sayHello(String name) {
        return helloProperties.getPrefix() + " say: hello - " + helloProperties.getSuffix();
    }
}

HelloService 的自动配置类

@Configuration
@ConditionalOnMissingBean(HelloService.class)
@EnableConfigurationProperties(HelloProperties.class) //默认 HelloProperties 放在容器中
public class HelloServiceAutoConfiguration {
    @Bean
    public HelloService helloService() {
        return new HelloService();
    }
}

resources/META-INF/spring.factories 

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.cj.hello.auto.HelloServiceAutoConfiguration

测试

创建一个 SpringBoot 项目,并引入 web 场景

引入自定义 starter 

        <!-- 引入`hello-spring-boot-starter`依赖 -->
        <dependency>
            <groupId>org.cj.hello</groupId>
            <artifactId>hello-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

定义 hello 场景的相关配置文件

hello.prefix = cj
hello.suffix = !!

编写测试 controller

@RestController
public class HelloController {
    @Autowired
    HelloService helloService;

    @GetMapping("/")
    public String hello() {
        return helloService.sayHello("home");
    }
}

最终页面输出为

  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值