Spring Boot从三到四
前面写了很多了关于SpringBoot入门的资料,这是第四篇。
1.面试官问:为什么SpringBoot的 jar 可以直接运行? (虽然不能算是入门了,但是进行了解,也有助于对整个框架的解释)
1.yml配置文件
(1) 定义多个配置文件
可以同时定义多个yml配置文件,比如:application-dev.yml、application-prod.yml、application-test.yml,通过在application.yml文件中定义:spring.profiles.active 属性,来区分要启动的配置文件,可以同时启动多个配置文件,比如:spring.profiles.active=dev,prod,test,后者与前者如果有相同的配置,则后者配置获胜,覆盖前者。
1 | spring: |
6.使用 spring.profiles.active 及 @profile 注解 动态化配置内部及外部配置
7.Spring Profiles
8.Spring Boot - Profile配置
(2) 定义和引用变量
如果一个字符串在yml中多次出现,则可以定义变量,通过变量的引用,就可以减少字符串的书写次数,也容易将字符串进行修改,修改一次字符串之后,其他的引用也都跟着变化了。yml中,引用变量的方式是通过${变量名}方式。在properties中,也是使用同样的方法进行变量引用。但是在引用pom.xml中变量还是有些区别的。
1 | app-name: test |
1.Spring Boot 利用 YAML 变量引用来简化配置
2.springboot 多模块情况下多配置文件问题
3.SpringBoot+Maven多模块项目(创建、依赖、打包可执行jar包部署测试)完整流程
4.03.SpringBoot的yml配置详解
5.springboot 配置文件中属性变量引用方式@@解析
6.在spring boot使用总结(九) 使用yaml语言来写配置文件
(3) yml引用pom.xml中的变量
在yml中引用pom.xml中的变量,需要两步
(1) pom.xml中添加
1 | <!--变量内容--> |
(2) 在application.yml配置文件中使用@@符合替换变量
1 | redis: |
(3) 进行打包
1 | mvn clean package |
这样resources下的application.yml
被打包之后的 tarcat/class 目录下的applcation.yml中的@@就会变成了相应的pom中的变量。在debug时,修改了pom.xml的值或者是yml中的值,除了重启应用程序之外,最好也执行一遍打包命令。
(4) 也可以增加自定义的属性,在pom.xml中的properties填写自定义的属性
1 | <properties> |
在application.yml中直接使用@tk@,引用pom.xml中的变量。
1.maven多个子项目、父项目之间的引用问题
2.yml、properties获取pom自定义变量
3.Spring-Boot application.yml 文件拆分,实现 maven 多环境动态启用 Profiles
4.SpringBoot配置文件yml(或properties)使用pom.xml中的变量 (仔细查看这个文章,里面有yml和properties中引用变量的方式)
5.在pom.xml中自定义变量及其使用
6.Maven打包时,环境变量替换,并解决spring-boot项目中${}无效的问题
7.application使用@符合问题:‘@’ that cannot start any token. (Do not use @ for indentation)
(4) 多模块的配置文件
如果各个模块都有自己的配置文件,就需要用到了多application.yml 合并选项。以A模块依赖于B和C模块为例,需要将B和C模块的配置文件整合到A模块的配置中。假设B模块的配置文件名为application-dev.yml,C模块的配置文件名为application-test.yml,需要将它们整合到A模块的配置文件application.yml中。
这里我本想引用 disasterapi 模块下的 src/main/resources/applicaion.yml 中的内容,结果总是找不到这个文件。使用 classpath:disasterapi/application.yml 也不行
1 | spring: |
最后的解决方案,就是将 application.yml 重命名为 application-disaster.yml,这样就可以直接找到这个文件了。
1 | spring: |
1.maven多模块多配置文件整合方案
2.SpringBoot使用spring.config.import多种方式导入配置文件
3.Spring Boot 分离配置文件的 N 种方式 1.配置文件位置:从 classpath 下加载;从项目所在的当前目录下加载;2.额外位置;3.位置通配符;4.导入外部配置。
4.springboot 多模块配置文件 这里直接在 classpath 中写了 modul1 的配置,这个我尝试了,没有效果。
5.如何配置SpringBoot多模块多环境配置文件 详细过程解析
4.properties中使用pom中的变量
(1) 在pom.xml中添加
1 | <build> |
(2) properties配置文件中使用项目的版本号
1 | app.version=${project.version} |
5.static静态方法中注入Bean
在静态方法中,只能使用静态的属性,所以需要
1.static静态方法内调用Spring(依赖注入)的bean 使用 @PostConstruct进行注入和使用set方法注入
2.springboot 静态方法注入bean、使用@value给static变量赋值
3.spring与springboot中,如何在static方法里用@Autowire或者@Resource注入的属性
6.读取配置文件
需求是这样的,就是我有多个properities文件,但是不是系统启动必须的文件,比如:application.properties或者是bootstrap.properities文件,是一些属性文件,比如:Error.properitis、Text.properities,里面也是:key=value 这种键值队的集合,当我想要某一个属性的时候,我想通过 getString(“key”) 这样的方法获取到这个键所对应的值,我也不需要使用 @ConfigurationProperties、@PropertySource 注解,单独的写一个配置文件类,这样得不偿失,因为我有时候可能并不是需要里面的值,所以你可以看成是一个单纯的文本文件,但是我想要用更加简单的方式读取出来。
使用 ResourceBundle textBundle = PropertyResourceBundle.getBundle(“Text”),这样的方式,在打包成jar包的时候可以使用,但是我在 SpringBoot 中使用,死活不行,就是读取不到resources文件夹下的相关文件。根据参考文章5,可以将properities文件放到src文件夹下,使用相对路径进行读取,但是我最终还是失败了。
1 | //config为属性文件名,放在包com.test.config下,如果是放在src下,直接用config即可 |
【解决方法】
这里我提供一种使用 Spring 提供的 PropertiesLoaderUtils 工具进行读取resource文件夹下的文件方法。
1 | Properties properties = new Properties(); |
这里主要的就是要研究 ClassPathResource 的用法。当然还有很多其他的方法,我就不一一实验了。
1.SpringBoot读取application.properties文件
2.Spring Boot读取多个自定义配置文件里的配置项内容 使用Environment env加载环境变量的信息
3.配置和读取多个Properties文件 这篇文章有点老了,是spring的,还是用的xml的形式进行配置的
4.如何在SpringBoot下读取自定义properties配置文件 使用的
5.Java 读取 .properties 配置文件的几种方式 这里有三种方法:基于ClassLoder读取配置文件、基于 InputStream 读取配置文件、通过 java.util.ResourceBundle 类来读取,这种方式比使用 Properties 要方便一些,这里还列举了各种不同的东西,但是我大部分都没有实验处理,主要是关于路径的问题,但是最后的加载方式,都是使用 Properties 这个类。
6.Spring工具类之PropertiesLoaderUtils 介绍了 PropertiesLoaderUtils 的用法,有好几种,但是始终还是
7.Spring项目读取resource下的文件 介绍了ClassPathResource的用法。
6.bootstrap文件
在 Spring Boot 中有两种上下文,一种是 bootstrap,另外一种是 application。
- bootstrap 是系统级的资源配置项,application是用户级的资源配置项。
- boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载。
- bootstrap 具有更高优先级,它不会被本地配置覆盖。
- bootstrap 主要用于负责从外部源加载配置属性并解析。
- 这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。
7.多模块共用一个相同配置文件
8.覆盖Bean
1.Bean 注册优先级:
- 具有 @ComponentScan注解的bean优先注册
- 具有 @Configuration 注解的bean
- 具有 @Controller @Service @Repository @Component 等常用注解的bean
- 被@Import注解导入的Bean
- 被 实现了ImportSelector接口的类导入的Bean
- 被 实现了ImportBeanDefinitionRegistrar接口的类导入的Bean
- 被 BeanDefinitionRegistry 动态注入的Bean (属于懒加载,在没有被Spring进行getBean查找时,不会执行初始化方法)
2.覆盖bean方法
(1)使用 @Primary 进行覆盖
(2)通过指定扫描顺序 @SpringBootApplication(scanBasePackages = {“com.dji.“,”com.openmap.“}),后面的覆盖前面的。
(3)使用 BeanDefinitionRegistryPostProcessor
1 |
|
(4)使用 @Order 定义 Bean 的顺序,Ordered / @Order 只控制执行顺序, 不控制Spring初始化Bean 的顺序
(5)排除需要替换的jar包中的类
(6)@ComponentScan(basePackages = {“com.dji.“,”com.openmap.“}),和SpringBootApplication一样,后面的包会覆盖前面的包,但是这个比SpringbootApplication优先级更高。
(7)使用Spring @DependsOn控制bean加载顺序
【1】.Spring Bean 的重写与覆盖 这里使用了 implements BeanDefinitionRegistryPostProcessor 配置的方法,就是直接使用 postProcessBeanDefinitionRegistry 方法,将注入的bean删除掉
【2】.覆盖重写 原有Spring Bean的几种方式 1.直接在自己工程中建同包同类名的类进行替换;2.采用@Primary注解;3.排除需要替换的jar包中的类;4.@Bean 覆盖;5.使用BeanDefinitionRegistryPostProcessor;
【3】.SpringBoot相同名称bean的覆盖问题 从SpringBoot 2.1.0开始,默认禁用bean名称相同时的覆盖行为。spring.main.allow-bean-definition-overriding=true
【4】.常见小bug之Spring @Configuration 注解未生效 在启动类中修改了自动扫描的包和子包,所以扫描失败了。
【5】.Spring | @Order 与 Ordered 控制加载顺序 Ordered / @Order 只控制执行顺序, 不控制Spring初始化Bean 的顺序
【6】.如何正确控制springboot中bean的加载顺序总结 而当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成自动装配时。你会声明自己的Configuration类,但是可能你面对的是好几个有互相依赖的Bean。如果不加以控制,这时候可能会报找不到依赖的错误。但是你明明已经把相关的Bean都注册进spring上下文了呀。这时候你需要通过一些手段来控制springboot中的bean加载顺序。 误区:1.在标注了@Configuration的类中,写在前面的@Bean一定会被先注册;2.利用@Order这个标注能进行加载顺序的控制,目前用的比较多的有以下3点:控制AOP的类的加载顺序,也就是被@Aspect标注的类;控制ApplicationListener实现类的加载顺序;控制CommandLineRunner实现类的加载顺序
【7】.Spring Bean 注册顺序优先级总结 @DependsOn;@Order;@Bean 方法参数注入;@AutoConfigureOrder;@AutoConfigureBefore 和 @AutoConfigureAfter
【8】.使用Spring @DependsOn控制bean加载顺序
【9】.SpringBoot教程(9) @DependsOn 设置Bean依赖 结合@Lazy 修改Bean加载顺序
【10】.Spring Boot |如何让你的 bean 在其他 bean 之前完成加载 这个 beanDefinitionNames 列表的顺序就决定了 Bean 的创建顺序,那么这个 beanDefinitionNames 列表又是怎么来的?答案是 ConfigurationClassPostProcessor 通过扫描你的代码和注解生成的,将 Bean 扫描解析成 Bean 定义(BeanDefinition),同时将 Bean 定义(BeanDefinition)注册到 BeanDefinitionRegistry 中,才有了 beanDefinitionNames 列表。