一、配置优先级
SpringBoot 中支持三种格式的配置文件:
注意事项
- 虽然 springboot 支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置 (yml 是主流)。
配置文件优先级排名(从高到低):
- properties 配置文件
- yml 配置文件
- yaml 配置文件
SpringBoot 除了支持配置文件属性配置,还支持 Java 系统属性 和 命令行参数 的方式进行属性配置。
优先级: 命令行参数 > 系统属性参数 > properties 参数 > yml 参数 > yaml 参数
项目已经打包上线了,这个时候我们又如何来设置Java系统属性和命令行参数呢?
注意事项
- Springboot 项目进行打包时,需要引入插件 spring-boot-maven-plugin (基于官网骨架创建项目,会自动添加该插件)
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
二、Bean 管理
1 获取 Bean
默认情况下,Spring 项目启动时,会把 bean 都创建好放在 IOC 容器中,如果想要主动获取这些 bean,可以通过如下方式:
- 根据 name 获取 bean:
Object getBean(String name)
- 根据类型获取 bean:
<T> T getBean(Class<T> requiredType)
- 根据 name获取 bean(带类型转换):
<T> T getBean(String name, Class<T> requiredType)
上述所说的 【Spring 项目启动时,会把其中的 bean 都创建好】还会受到作用域及延迟初始化影响,这里主要针对于 默认的单例非延迟加载的 bean 而言。
@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
//获取bean对象
@Test
public void testGetBean(){
//根据bean的名称获取
DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
System.out.println(bean1);
//根据bean的类型获取
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);
//根据bean的名称 及 类型获取
DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
System.out.println(bean3);
}
}
2 Bean 作用域
Spring 支持五种作用域
可以通过 @Scope 注解来进行配置作用域:
//@Lazy
@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
}
注意事项:
- 默认 singleton 的 bean,在容器启动时被创建,可以使用 @Lazy 注解来延迟初始化(延迟到第一次使用时)。
- prototype 的 bean,每一次使用该 bean 的时候都会创建一个新的实例。
- 实际开发当中,绝大部分的 Bean 是单例的,也就是说绝大部分 Bean 不需要配置 scope 属性。
@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
//bean的作用域
@Test
public void testScope(){
for (int i = 0; i < 10; i++) {
DeptController deptController = applicationContext.getBean(DeptController.class);
System.out.println(deptController);
}
}
}
3 第三方 Bean
如果要管理的 bean 对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明 bean 的,就需要用到 @Bean 注解。
解决方案1:在启动类上添加 @Bean 标识的方法(不建议,项目中要保证启动类的纯粹性)
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
public SAXReader saxReader(){
return new SAXReader();
}
}
@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
@Autowired
private SAXReader saxReader;
//第三方bean的管理
@Test
public void testThirdBean() throws Exception {
//SAXReader saxReader = new SAXReader();
Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.println(name + " : " + age);
}
}
解决方案2:在配置类中定义 @Bean 标识的方法
- 若要管理的第三方 bean 对象,建议对这些 bean 进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。
@Configuration //配置类
public class CommonConfig {
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名
public SAXReader reader(DeptService deptService){
System.out.println(deptService);
return new SAXReader();
}
}
注意事项:
- 通过 @Bean 注解的 name 或 value 属性可以声明 bean 的名称,如果不指定,默认 bean 的名称就是方法名。
- 如果第三方 bean 需要依赖其它 bean 对象,直接在 bean 定义方法中设置形参即可,容器会根据类型自动装配。
@Component 及衍生注解 与 @Bean 注解使用场景?
- 项目中自定义的,使用 @Component 及其衍生注解
- 项目中引入第三方的,使用 @Bean 注解
三、SpringBoot 原理
通过 SpringBoot 来简化 Spring 框架的开发(是简化不是替代)。我们直接基于 SpringBoot 来构建 Java 项目,会让我们的项目开发更加简单,更加快捷。
- 通过 SpringBoot 所提供的起步依赖,就可以大大的简化 pom 文件当中依赖的配置,从而解决了 Spring 框架当中依赖配置繁琐的问题。
- 通过自动配置的功能就可以大大的简化框架在使用时 bean 的声明以及 bean 的配置。我们只需要引入程序开发时所需要的起步依赖,项目开发时所用到常见的配置都已经有了,我们直接使用就可以了。
1 起步依赖
为什么我们只需要引入一个 web 开发的起步依赖,web 开发所需要的所有的依赖都有了呢?
- 因为 Maven 的依赖传递。
- 在 SpringBoot 给我们提供的这些起步依赖当中,已提供了当前程序开发所需要的所有的常见依赖(官网地址:https://docs.spring.io/spring-boot/docs/2.7.7/referen
ce/htmlsingle/#using.build-systems.starters )。- 比如:springboot-starter-web,这是 web 开发的起步依赖,在 web 开发的起步依赖当中,就集成了 web 开发中常见的依赖:json、web、webmvc、tomcat等。我们只需要引入这一个起步依赖,其他的依赖都会自动的通过 Maven 的依赖传递进来。
结论:起步依赖的原理就是 Maven 的依赖传递。
2 自动配置
2.1 概述
SpringBoot 的自动配置就是当 spring 容器启动后,一些配置类、bean 对象就自动存入到了 IOC 容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
2.2 方案一,@ComponentScan 组件扫描
@ComponentScan({"com.example","com.itheima"})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}
缺点:
- 使用繁琐
- 性能低
2.3 方案二,@Import 导入
使用 @Import 导入的类会被Spring加载到IOC容器中,导入形式主要有以下几种:
- 导入 普通类
- 导入 配置类
- 导入 ImportSelector 接口实现类
- @EnableXxxx 注解,封装 @Import 注解
//@Import({TokenParser.class})//导入普通类,交给IOC容器管理
//@Import({HeaderConfig.class})//导入配置类,交给IOC容器管理
@Import({MyImportSelector.class})//导入ImportSelector接口实现类,交给IOC容器管理
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}
@EnableHeaderConfig
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableHeaderConfig {
}
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.HeaderConfig"};
}
}
2.4 原理分析
2.4.1 源码跟踪
@SpringBootApplication
该注解标识在 SpringBoot 工程引导类上,是 SpringBoot 中 最最最重要 的注解。该注解由三个部分组成:
- @SpringBootConfiguration:该注解与 @Configuration 注解作用相同,用来声明当前也是一个配置类。
- @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包。
- @EnableAutoConfiguration:SpringBoot 实现自动化配置的核心注解。
2.4.2 @Conditional
- 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的 bean 对象到 Spring IOC 容器中。
- 位置:方法、类
- @Conditional 本身是一个父注解,派生出大量的子注解:
1️⃣@ConditionalOnClass:判断环境中是否有对应字节码文件,才注册 bean 到 IOC 容器。
2️⃣ @ConditionalOnMissingBean:判断环境中没有对应的 bean(类型 或 名称) ,才注册 bean 到 IOC 容器。
3️⃣ @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册 bean 到 IOC 容器。
@Configuration
public class HeaderConfig {
@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts")// 环境中存在指定的这个类,才会将该bean加入IOC容器
public HeaderParser headerParser1(){
return new HeaderParser();
}
@Bean
// @ConditionalOnMissingBean //当不存在当前类型(HeaderGenerator)的bean时,才声明该bean
// @ConditionalOnMissingBean(name = "deptController2") //不存在指定名称的bean,才会将该bean加入IOC容器
@ConditionalOnMissingBean(HeaderConfig.class)//不存在指定类型的bean,才会将bean加入IOC容器
public HeaderGenerator headerGenerator(){
return new HeaderGenerator();
}
@Bean
@ConditionalOnProperty(name = "name" ,havingValue = "itheima")//配置文件中存在指定的属性与值,才会将该bean加入IOC容器
public HeaderParser headerParser2(){
return new HeaderParser();
}
}