• 0

  • 498

  • Favorite

从零教你学Spring Boot(一)

7 months ago

Spring Boot学习教程(一)

1.SpringBoot入门

简介

背景

SpringBoot 用来简化 Spring 应用开发 是整个 Spring 技术栈的一个大整合 是 J2EE 开发的一站式解决方案

优点

  • 快速创建独立运行的 Spring 项目以及与主流框架集成
  • 使用嵌入式的 Servlet 容器,应用无需打包成 WAR
  • starters 帮助我们实现自动依赖与版本控制
  • 大量的自动配置,简化开发,也可以修改默认值
  • 无需配置 XML ,无代码生成,开箱即用
  • 提供准生产环境的运行时应用监控
  • 与云计算的天然集成

微服务简介

微服务是一种架构风格 一个应用应该是一组小型服务,可以通过HTTP的方式进行互通 每一个功能元素最终都是一个可以独立替换和可独立升级的软件单元

微服务架构vs单体应用架构

单体应用(All in one)

  • 优点
  1. 便于共享:单个归档文件包含所有功能,便于在团队之间以及不同的部署阶段之间共享。
  2. 易于测试:单体应用一旦部署,所有的服务或特性就都可以使用了,这简化了测试过程,因为没有额外的依赖,每项测试都可以在部署完成后立刻开始。
  3. 易于部署:只需将单个归档文件复制到单个目录下。
  • 缺点
  1. 复杂性高:由于是单个归档文件,所以整个项目文件包含的模块非常多,导致模块的边界模糊、依赖关系不清晰、代码的质量参差不齐,混乱的堆在一起,使得整个项目非常复杂。以致每次修改代码,都非常小心,可能添加一个简单的功能,或者修改一个bug都会带来隐藏的缺陷。
  2. 技术债务:随着时间的推移、需求的变更和技术人员的更替,会逐渐形成应用程序的技术债务,并且越积越多。
  3. 扩展能力受限:单体应用只能作为一个整体进行扩展,无法根据业务模块的需要进行伸缩。
  4. 阻碍技术创新:对于单体应用来说,技术是在开发之前经过慎重评估后选定的,每个团队成员都必须使用相同的开发语言、持久化存储及消息系统。
0VuDFU.png

微服务

  • 优点
  1. 易于开发和维护:一个微服务只会关注一个特定的业务功能,所以业务清晰、代码量较少。开发和维护单个微服务相对简单。
  2. 单个微服务启动较快
  3. 局部修改容易部署:单体应用只要有修改,就得重新部署整个应用。微服务解决了这样的问题。一般来说,对某个微服务进行修改,只需要重新部署这个服务即可。
  4. 技术栈不受限制:在微服务架构中,可以结合项目业务及团队的特点,合理的选择技术栈。
  5. 按需伸缩:可根据需求,实现细粒度的扩展。
  • 缺点
  1. 运维要求高:更多的服务意味着要投入更多的运维。
  2. 分布式固有的复杂性:使用微服务构建的是分布式系统。对于一个分布式系统,系统容错、网络延迟、分布式事务等都会带来巨大的问题。
  3. 接口调整成本高:微服务之间通过接口进行通信。如果修改某一个微服务的API,可能所有用到这个接口的微服务都需要进行调整。
0VuwwV.png

环境准备

1. Maven设置

找到maven的文件夹,找到bin/conf/settings.xml配置文件 然后找到 profiles 标签,添加以下配置:


<profile>
   <id>jdk-1.8</id>
    <activation>
        <activeByDefault>true</activeByDefault>
        <jdk>1.8</jdk>
    </activation>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>        
</profile>

复制代码

2. IDEA设置

  • Step1

    0AtMan.png
  • Step2

    0AtNqJ.png
  • Step3

    0AtaZ9.png

SpringBoot-HelloWorld

目标功能: 浏览器发送 hello 请求,服务器接受请求并处理,相应 Hello World 字符串

1. 创建一个maven工程(jar)

0Vffkn.png
0VfIpV.png

2. 导入SpringBoot相关的依赖


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

复制代码

3. 编写一个主程序:用于启动SpringBoot应用


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/*
* @SpringBootApplication 用来标注一个主程序类,说明这是一个Spring Boot应用
 */

@SpringBootApplication
public class HelloWorldMainApplication {

    public static void main(String[] args) {
        //Spring应用启动起来
        SpringApplication.run(HelloWorldMainApplication.class,aargs);
    }
}

复制代码

4. 编写相关的Controller、Service


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @ResponseBody
    @RequestMapping("/hello")
    public String hello(){
        return "Hello World!";
    }
}

复制代码

5. 运行主程序测试

运行结果:

0AtsxO.png

6. 简化部署

导入插件:


<!-- 这个插件,可以将应用打包成一个可执行的jar包 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.4.RELEASE</version>
            </plugin>
        </plugins>
    </build>

复制代码

将这个应用打包成jar包,直接使用 java -jar 命令执行:

0ERfLd.png
0EWNkt.png
0E2wUP.png

运行结果:

0EWUtP.png

Hello World探究

1. POM文件分析

a. 父项目

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
    </parent>

复制代码

spring-boot-starter-parent 的父项目是:


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.3.RELEASE</version>
</parent>

复制代码

它真正管理了Spring Boot应用里的所有依赖版本,所以称为Spring Boot的版本仲裁中心

所以我们导入依赖的时候默认是不需要写版本的,因为已经都预设好了的 (不过也有些没有在dependencies里面管理的依赖,这些依赖就需要声明版本号)

b. 导入的依赖

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

复制代码

关于spring-boot-starter-web:

  • spring-boot-starter:spring-boot场景启动器 作用:帮我们导入了web模块要正常运行所依赖的组件

Spring Boot将所有的功能场景都抽取出来,做成一个个的starter(启动器),当我们需要用到这些功能场景时,只需要在项目中引入这些starter,这样相关场景的所有依赖都会被导入进来。 要用什么功能,就导入什么场景启动器。

2. 主程序类(主入口类)

1. @SpringBootApplication

/*
* @SpringBootApplication 用来标注一个主程序类,说明这是一个Spring Boot应用
 */

@SpringBootApplication
public class HelloWorldMainApplication {

    public static void main(String[] args) {
        //Spring应用启动起来
        SpringApplication.run(HelloWorldMainApplication.class,args);
    }
}

复制代码
@SpringBootApplication

Spring Boot应用标注

标注在某个类上说明这个类是Spring Boot的主配置类,Spring Boot应该运行这个类的main方法来启动Spring Boot应用

注解 @SpringBootApplication 部分源码:


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

复制代码

其中有很多注解:

1.1 @SpringBootConfiguration

Spring Boot的配置类

标注在某个类上,表示这是一个Sprin Boot的配置类

注解 @SpringBootConfiguration 部分源码:


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

复制代码

其中又有很多注解:

1.1.1 @Configuration

表明注解后的那个类是一个配置类 配置类相当于Spring中的配置文件 配置类也是容器中的一个组件(@Componet

1.2 @EnableAutoConfiguration

告诉Spring Boot开启自动配置功能,这样自动配置才能生效 Spring中需要手动配置的东西,Spring Boot帮我们自动配置

注解 @EnableAutoConfiguration 部分源码


@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

复制代码

其中又有很多注解:

1.2.1 @AutoConfigurationPackage

自动配置包 @Import({Registrar.class})

Spring 的底层注解,向容器中导入一个组件 导入的组件由Registrar.class决定 将主配置类( @SpringBootApplication 标注的类)的所在包及其所有子包中的所有组件扫描到 Spring 容器中

1.2.2 @Import({AutoConfigurationImportSelector.class}):

给容器中导入AutoConfigurationImportSelector组件

AutoConfigurationImportSelector :选择导入哪些组件的选择器

注解 @AutoConfigurationImportSelector 部分源码:


public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

复制代码

将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中 会给容器中导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件

打断点,debug模式运行

0VxhqA.png
0VxIat.png
0Vx7Pf.png

有了这些自动配置类,免去了我们手动编写配置注入功能组件等的工作;

    SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
复制代码

Spring Boot 在启动的时候从类路径下的 META-INF/spring.factories 中获取 EnableAutoConfiguration 指定的值,将这些值作为自动配置类,导入到容器中,于是自动配置类就能生效,就能帮我们进行自动配置工作

J2EE的整体整合解决方案和自动配置,都在spring-boot-autoconfigure-2.3.3.RELEASE.jar

使用Spring Initializer快速创建Spring Boot项目

IDEA支持使用Spring的项目创建向导快速创建一个Spring Boot项目

0VDqPg.png
0VDO2j.png

选择需要的模块(这里以Spring Web为例)

0VriiF.png

向导会联网创建Spring Boot项目

0VDzq0.png

运行结果:

0VrFG4.png

默认生成的Spring Boot项目:

  • 主程序已经生成好了,我们只需要编写我们自己的业务逻辑
  • resource文件夹中的目录结构:
    • static: 保存所有的静态资源(js,css,images)
    • templates: 保存了所有的模板页面(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引擎(如freemarker、thymeleaf)
    • application.properties:Spring Boot应用的配置文件;可以修改一些默认设置

2.SpringBoot配置

配置文件

Spring Boot使用一个全局的配置文件,配置文件名是固定的,有两种形式的全局配置文件:

  • application.properties
  • application.yml

配置文件的作用:修改Spring Boot自动配置的默认值 Spring Boot在底层都给我们配置好了默认值

什么是yml文件呢?

ymlYAML(YAML Ain't Markup Language) 语言的文件,以数据为中心,比json、xml等更适合做配置文件

标记语言(Markup Language): 以前的配置文件大多数都是用xml文件,xml就是一种“可拓展标记语言”

YAML配置实例:


server:
  port: 8082

复制代码

XML配置实例:


<server>
    <port>8082</port>
</server>

复制代码

YAML语法

1. 基本语法


k: v
# 表示一对键值对(空格必须有)

复制代码

server:
    port: 8081
    path: /hello
# 以空格的缩进来控制层级关系
# 只要是左对齐的一列数据,都是同一个层级的
复制代码

属性和值也是大小写敏感

2. 值的写法

  • 字面量:普通的值(数字、字符串、布尔)

k: v
# 直接写
# 字符串默认不用加上单引号或者双引号

name: "taotao \n zeng"
# 双引号中的字符不会转义特殊字符,所以特殊字符会起到它想表达的特殊作用
# 输出为:
# taotao
# zeng

name1: 'taotao \n zeng'
# 单引号中的字符会转义特殊字符,特殊字符最终只是一个普通的字符串数据
# 输出为:
# taotao \n zeng
复制代码
  • 对象、Map(属性和值)(键值对):

k: v
# 对象的表示还是键值对的方式

# 多行写法:
# 注意缩进
friends:
    lastName: z
    age: 20


# 单行写法:
frineds: {lastname: z,age: 20}

复制代码
  • 数组(List、Set):

用- 值表示数组中的一个元素


# 单行写法:
pets:
    - cat
    - dog
    - pig

# 多行写法:
pets: [cat,dog,pig]

复制代码

配置文件值注入

配置文件


person:
  lastName: taotao
  age: 18
  boss: true
  birth: 2000/05/04
  maps: {k1: v1,k2: 12}
  lists:
    - taotao
    - xiaotao
  dog:
    name: wangxun
    age: 2

复制代码

javaBean:


/*
* 将配置文件中配置的每一个属性的值映射到这个组件中
* @ConfigurationProperties:告诉Spring Boot将本类中的所有属性和配置文件中相关的配置进行绑定
*   prefix = "person":指明了与配置文件中哪个标签下面的所有属性进行一一映射
*
* 只有当这个组件是容器中的组件时,才能使用容器提供的@ConfigurationProperties功能
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {

    private String lastName;
    private Integer age;
    private Boolean boss;
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;


复制代码

可以导入配置文件处理器,以后编写配置就会有提示


<!--导入配置文件处理器,配置文件进行绑定时就会有提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

复制代码

@Value获取值和@ConfigurationProperties获取值的比较

name @ConfigurationProperties @Value
功能 批量注入配置文集中的属性 必须一个一个指定
是否支持松散绑定(松散语法)
是否支持SpEL
是否支持JSR303数据校验
是否支持复杂类型封装

如何在两种获取值的方式之间选择呢?

  • 如果我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,比较倾向于使用 @Value
  • 如果我们专门编写了一个javaBean来和配置文件进行映射,那就比较倾向于 @ConfigurationProperties

松散绑定(松散语法): 在松散语法中,以下表达式皆等价:

  • person.firstName:标准方式,驼峰命名
  • person.first-name:-表示后接大写字母
  • person.firstname:表示后接大写字母
  • person_FIRST_NAME

总的来说,不管是配置文件yml还是properties,他们都能去获取值

@PropertySource & @ImportResource

@PropertySource:加载指定的配置文件 @ConfigurationProperties默认从全局配置文件中获取值


package com.taotao.springboot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import java.util.Date;
import java.util.List;
import java.util.Map;

/*
* 将配置文件中配置的每一个属性的值映射到这个组件中
* @ConfigurationProperties:告诉Spring Boot将本类中的所有属性和配置文件中相关的配置进行绑定
*   prefix = "person":指明了与配置文件中哪个标签下面的所有属性进行一一映射
*
* 只有当这个组件是容器中的组件时,才能使用容器提供的@ConfigurationProperties功能
*/
@PropertySource(value = "classpath:person.properties")
@Component
@ConfigurationProperties(prefix = "person")
//@Validated
public class Person {

    /*
    * <bean class = "Person">
    *   <property name = "LastName" value = "字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
    * </bean>
    */
    //@Value("${person.last-name}")
    private String lastName;
    //@Value("#{11*2}")
    private Integer age;
    //@Value("true")
    private Boolean boss;
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}

复制代码

@ImportResource:导入Spring的配置文件,让配置文件中的内容生效 为什么需要 @ImportResource 呢?因为Spring Boot中没有Spring的配置文件,我们自己编写的配置文件也不能被自动识别

不信你看:

//HelloService.java

public class HelloService {
}

复制代码
<!-- beans.xml -->

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="helloService" class="com.taotao.springboot.service.HelloService"></bean>
</beans>

复制代码
//测试类

@SpringBootTest
class SpringBoot02ConfigApplicationTests {

    @Autowired
    Person person;

    @Autowired
    ApplicationContext ioc;

    @Test
    public void testHelloService(){
        boolean b = ioc.containsBean("helloService");
        System.out.println(b);
    }

    @Test
    void contextLoads() {
        System.out.println(person);
    }
}

复制代码

所以,想让Spring的配置文件生效并加载进来,我们便需要将 @ImportResource 标注在一个配置类上

//SpringBoot02ConfigApplication.java

@ImportResource(locations = {"classpath:beans.xml"})
@SpringBootApplication
public class SpringBoot02ConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot02ConfigApplication.class, args);
    }

}

复制代码

然而,这种方法太麻烦啦,所以Spring Boot推荐的给容器中添加组件的方式是——使用全注解的方式:

  • Step1: 编写配置类(配置类跟Spring配置文件作用相同)
  • Step2: 使用@Bean给容器中添加组件

看看代码

//MyAppConfig.java

@Configuration
public class MyAppConfig {

    //将方法的返回值添加到容器中,容器中这个组件默认的id就是方法名
    @Bean
    public HelloService helloService(){
        System.out.println("配置类@Bean给容器中添加了组件");
        return new HelloService();
    }
}

复制代码

@SpringBootTest
class SpringBoot02ConfigApplicationTests {

    @Autowired
    Person person;

    @Autowired
    ApplicationContext ioc;

    @Test
    public void testHelloService(){
        boolean b = ioc.containsBean("helloService");
        System.out.println(b);
    }

    @Test
    void contextLoads() {
        System.out.println(person);
    }

}

复制代码

测试结果:

0EPAb9.png

关于id与方法名:


//MyAppConfig.java

@Configuration
public class MyAppConfig {

    //将方法的返回值添加到容器中,容器中这个组件默认的id就是方法名
    @Bean
    public HelloService helloService02(){
        System.out.println("配置类@Bean给容器中添加了组件");
        return new HelloService();
    }
}

复制代码

测试结果:

0EPZU1.png

配置文件占位符

  1. 随机数

${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int[1024,65536]}

复制代码
  1. 可以用占位符来获取之前配置的值,如果没有配置值,可以使用 ${k:v} 指定默认值

# application.properties

person.last-name=张三${random.uuid}
# 
person.age=${random.int}
person.birth=2000/05/04
person.boss=true
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.last-name}_dog
person.dog.age=15

复制代码

测试结果:

0EQQH0.png

默认值


# application.properties

person.last-name=张三${random.uuid}
person.age=${random.int}
person.birth=2000/05/04
person.boss=true
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15

复制代码

测试结果:

0EQ84U.png

Profile

Profile是Spring对不同环境(开发环境、测试环境、生产环境等)提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境

  1. profile文件形式:

我们在编写主配置文件的时候,文件名可以是 application-{profile}.properties/yml

默认使用 application.properties中的配置

不信你看:

//application.properties

server.port=8081

复制代码
//application-dev.properties

server.port=8081

复制代码
//application-prod.properties

server.port=8081

复制代码

运行结果:

0E3zIP.png

server.port=8081
spring.profiles.active=dev

复制代码

运行结果:

0E8CRS.png
  1. yml支持的多profile文档块模式

补充一个yaml语法: 可以用 --- 来分割代码以形成文档块

# appplication.yml

server:
  port: 8081
spring:
  profiles:
    active: dev
    # 激活

---
server:
  port: 8083
spring:
  profiles: dev

---
server:
  port: 8084
spring:
  profiles: prod

复制代码

运行结果:

0ENyP1.png
  1. 激活方式:
  • 在配置文件中指定来激活
  1. properties文件中
spring.profiles.active = dev
复制代码

  1. yaml文件中
server:
  port: 8081
spring:
  profiles:
    active: dev
    # 激活
复制代码
  • 命令行方式激活 而且命令行参数优先级高一些 不信你看:

可以直接在测试的时候,传program arguments: --spring.profiles.active=dev

0E0ZX6.png

设置命令行参数:

0E039A.png

运行结果:

0E0Gct.png

也可以在测试的时候,传虚拟机参数(VM options): -Dspring.profiles.active=dev

输入虚拟机参数:

0EsyiF.png

运行结果:

0EsRMR.png

还可以打包成jar包后来设置命令行参数:

打包成jar包:

0Eru7T.png

找到jar包并输入命令行参数:

0EsAUO.png
0Esm2d.png

运行结果:

0EsYGQ.png

配置文件加载位置

Spring Boot启动时会扫描一下位置的application.properties或者application.yml文件作为Spring Boot的默认配置文件

优先级从高到低:

  • file:./config/(文件路径下的config文件夹下)
  • file:./(文件路径下)
  • classpath:/config/(类路径下的config文件夹下)
  • classpath:/(类路径下)

所有位置的文件都会被加载,但是高优先级的配置内容会覆盖低优先级的配置内容 不信你看:

  • classpath:/(类路径下)
0ETF4s.png
  • classpath:/config/(类路径下的config文件夹下)
0ETwUH.png
  • file:./(文件路径下)
0ETXa4.png
  • file:./config/(文件路径下的config文件夹下)
0ETzGR.png

注意:Spring Boot会从这四个位置全部加载主配置文件,会形成互补配置 也就是,假如高优先级位置文件没有进行某项配置A,只配置了B,而低优先级位置的配置文件中A和B两项都进行了配置的话,则会互补 最终加载的配置是:低A+高B

另外,我们还可以通过配置spring.config.location来改变默认配置: 项目打包好以后,我们可以以命令行参数的形式,在启动项目的时候来指定配置文件的新位置 被指定配置文件和默认加载的配置文件共同起作用且形成互补配置

打包好后,复制一份application.properties到桌面:

0VkPyT.png

修改配置

0VkJkd.png

运行结果:

0VkYtA.png

外部配置加载顺序

Spring Boot支持多种外部配置方式:(下面举例部分方式,加粗的为常用方式

Spring Boot也可以从以下位置加载配置,优先级从高到低,高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置

  1. 命令行参数
  2. 来自java:comp/env的JNDI属性
  3. Java系统属性(System.getProperties())
  4. 操作系统环境变量
  5. RandomValuePropertySource配置的random.*属性值
  6. jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
  7. jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
  8. jar包外部的application.properties或application.yml(不带spring.profile)配置文件
  9. jar包内部的application.properties或application.yml(不带spring.profile)配置文件
  10. @Configuration注解类上的@PropertySource
  11. 通过SpringApplication.setDefaultProperties指定的默认属性

示例:

  1. 命令行参数 格式:java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
0ZaUAg.png

6~9总结:优先加载带profile的,后加载不带profile的

  1. jar包 外部 的application.properties或application.yml(不带spring.profile)配置文件
0ZdXZT.png
0Z0EXq.png
0ZwaSs.png

详见官方文档~有时间会补充完整的!

自动配置原理

配置文件里能写点啥?

官方文档Common Application properties-配置文件能配置的属性参照

自动配置的原理是什么?

  1. Spring Boot启动的时候加载主配置类,开启了自动配置功能( @EnableAutoConfiguration )
  2. @EnableAutoConfiguration的作用: 利用 AutoConfigurationImportSelector 向容器中导入一些组件 AutoConfigurationImportSelector 向容器中导入了哪些组件呢? 可以通过查看 selectImports() 方法的内容来获知
0eXcxe.png
0eX2KH.png

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    //扫描所有jar包类路径下的META-INF/spring.factories文件
    //然后把扫描到的这些文件的内容包装成一个properties对象
    //从properties中获取到EnableAutoConfiguration类对应的值,然后把它们添加在容器中
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

复制代码

将类路径下 META-INF/spring.factories 里面配置的所有 EnableAutoConfiguration 的值加入到容器中 有这么多自动配置:


# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

复制代码

每一个这样的 xxxAutoConfiguration 类都是容器中的一个组件,都加入到容器中,用他们来做自动配置

  1. 每一个自动配置类实现自动配置功能

举个例子:(以 HttpEncodingAutoConfiguration 为例,解释自动配置原理)


org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\

复制代码

自动配置类HttpEncodingAutoConfiguration 的源码:


@Configuration(
    proxyBeanMethods = false
)   //表示这是一个配置类
@EnableConfigurationProperties({ServerProperties.class})    //启用指定类的ConfigurationProperties功能,将配置文件中对应的值和ServerProperties绑定起来,并把ServerProperties加入到IOC容器中
@ConditionalOnWebApplication(
    type = Type.SERVLET
)   //基于Spring底层@Conditional注解,根据不同的条件进行判定:如果满足指定的条件(判断当前应用是否是web应用),整个配置类中的配置才会生效
@ConditionalOnClass({CharacterEncodingFilter.class})    //判定当前项目是否有CharacterEncodingFilter类(是SpringMVC中进行乱码解决的过滤器)
@ConditionalOnProperty(
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)   //判断配置文件中是否存在某些配置(提供了默认值)
public class HttpEncodingAutoConfiguration {
    private final Encoding properties;  //它已经和Spring Boot的配置文件映射了

    //在只有一个游蚕构造器的情况下,参数的值就会从容器中获取(通过@EnableConfigurationProperties注解)
    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }

    @Bean   //往容器中添加一个组件,这个组件的某些值需要从properties中获取
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
    }

    @Bean
    public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
    }

    static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
        private final Encoding properties;

        LocaleCharsetMappingsCustomizer(Encoding properties) {
            this.properties = properties;
        }

        public void customize(ConfigurableServletWebServerFactory factory) {
            if (this.properties.getMapping() != null) {
                factory.setLocaleCharsetMappings(this.properties.getMapping());
            }

        }

        public int getOrder() {
            return 0;
        }
    }
}


复制代码

一旦这个配置类生效,这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的properties类中获取的,这里的类里面每一个属性又是和配置文件绑定的

  1. 所有在配置文件中能配置的属性都在 xxxProperties 类中封装着;想知道某个配置文件能配置什么,就可以参照该功能对应的属性类

在上方的 HttpEncodingAutoConfiguration 源码中,我们点进注解 @EnableConfigurationProperties 中的 ServerProperties 类:


@ConfigurationProperties(
    prefix = "server",
    ignoreUnknownFields = true
)   //从配置文件汇总获取指定的值和bean的属性进行绑定
public class ServerProperties {

复制代码

可配置项例子:( 我们能配置的属性都是来源于这个功能的properties类

0mSsjU.png
0mStBQ.png

Spring Boot的精髓

1. Spring Boot启动会加载大量的配置类 2. 我们要查看我们需要的功能有没有Spring Boot默认写好的自动配置类

查找方法:ctrl+n,输入AutoConfiguration就可以查看有哪些自动配置了

3.如果有写好的自动配置类,那我们就再来看这个自动配置类中到底配置了哪些组件(就不用自己配置了,如果没有,就得自己写配置类了) 4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们就可以在配置文件中指定这些属性的值

@Conditional & 自动配置报告

  1. @Conditional派生注解(Spring注解版原生的@Conditional作用)

作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置类里面的所有内容平才会生效

Spring Boot中@Conditional的拓展注解:

@Conditional的拓展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的Java版本是否符合要求
@ConditionalOnBean 容器中存在指定bean
@ConditionalOnMissingBean 容器中不存在指定bean
@ConditionalOnExpression 满足SpEL表达式
@ConditionalOnClass 系统中有指定的类
@ConditionalOnSingleCandidate 系统中没有指定的类
@ConditionalOnMissingClass 容器中只有一个指定的bean,或者这个bean是首选bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

自动配置类必须在一定的条件下才能生效

我们可以通过启用 debug=true 属性,来让控制台打印自动配置报告,这样就可以很方便地知道哪些自动配置类生效了,哪些没有生效

# application.properties

# 开启Spring Boot的debug模式
debug=true

复制代码
0ebpTK.png
0ebPYD.png
0ebkSH.png
0ebE6A.png
0ebm0P.png
免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

物联网

498

Relevant articles

未登录头像

No more data