SpringBoot2.4.0总结,自动装配原理解析

SpringBoot

SpringBoot简介

回顾什么是Spring

Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架,作者:Rod Johnson 。

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

  1. 基于POJO的轻量级和最小侵入性编程,所有东西都是bean

  2. 通过IOC,依赖注入(DI)和面向接口实现松耦合

  3. 基于切面(AOP)和惯例进行声明式编程

  4. 通过切面和模版减少样式代码,RedisTemplate,xxxTemplate

什么是SpringBoot

它是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置

Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用

简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架

SpringBoot的主要优点
  • 为所有Spring开发者更快的入门
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

第一个SpringBoot程序

准备工作

环境准备:

  • java version “1.8.0_181”
  • Maven-3.6.1
  • SpringBoot 2.4.0 最新版

开发工具:

  • IDEA
创建项目

**项目创建方式一:**使用Spring Initializr 的 Web页面创建项目

  1. 打开 https://start.spring.io/

  2. 填写项目信息

  3. 点击”Generate Project“按钮生成项目;下载此项目

  4. 解压项目包,并用IDEA以Maven项目导入,一路下一步即可,直到项目导入完毕。

  5. 如果是第一次使用,可能速度会比较慢,包比较多、需要耐心等待一切就绪

**项目创建方式二:**使用 IDEA 直接创建项目

  1. 创建一个新项目

  2. 选择spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现

SpringBoot2.4.0总结,自动装配原理解析_第1张图片

  1. 填写项目信息,项目名为springboot-01-helloworld

SpringBoot2.4.0总结,自动装配原理解析_第2张图片

  1. 选择初始化的组件(初学勾选 Web 即可)

SpringBoot2.4.0总结,自动装配原理解析_第3张图片

  1. 填写项目路径

SpringBoot2.4.0总结,自动装配原理解析_第4张图片

  1. 等待项目构建成功

项目结构分析:

通过上面步骤完成了基础项目的创建。就会自动生成以下文件。

1、程序的主启动类

2、一个 application.properties 配置文件

3、一个 测试类

4、一个 pom.xml

SpringBoot2.4.0总结,自动装配原理解析_第5张图片

pom.xml分析

打开pom.xml,看看Spring Boot项目的依赖:


<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.0modelVersion>
    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.4.0version>
        <relativePath/> 
    parent>
    <groupId>com.chygroupId>
    <artifactId>springboot-01-helloworldartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>springboot-01-helloworldname>
    <description>first springboot projectdescription>

    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

    <build>
        <plugins>
            
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>
编写一个http接口
  1. 在主程序的同级目录下,新建一个controller包,一定要在同级目录下,否则识别不到

  2. 在包中新建一个HelloController

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "Hello World";
    }
}
  1. 编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回;控制台输出了 Tomcat 访问的端口号!

SpringBoot2.4.0总结,自动装配原理解析_第6张图片

SpringBoot2.4.0总结,自动装配原理解析_第7张图片

简单几步,就完成了一个web接口的开发,SpringBoot就是这么简单。所以我们常用它来建立我们的微服务项目!

更改启动Banner

如何更改启动时显示的字符拼成的字母,SpringBoot呢?也就是 banner 图案;

只需一步:到项目下的 resources 目录下新建一个banner.txt 即可。

SpringBoot2.4.0总结,自动装配原理解析_第8张图片

图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!

测试启动

SpringBoot2.4.0总结,自动装配原理解析_第9张图片

运行原理探究

我们之前写的HelloSpringBoot,到底是怎么运行的呢,Maven项目,我们一般从pom.xml文件探究起

pom.xml

父依赖

其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!


<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.4.0version>
    <relativePath/> 
parent>

点进去,发现还有一个父依赖

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-dependenciesartifactId>
    <version>2.4.0version>
parent>

这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心

SpringBoot2.4.0总结,自动装配原理解析_第10张图片

以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了

启动器 spring-boot-starter


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

springboot-boot-starter-xxx:就是spring-boot的场景启动器

spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组;

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter

主启动类

默认的主启动类

// @SpringBootApplication 来标注一个主程序类
// 说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
    
   public static void main(String[] args) {
      // 以为是启动了一个方法,没想到启动了一个服务
      SpringApplication.run(SpringbootApplication.class, args);
   }

}

但是**一个简单的启动类并不简单!**我们来分析一下这些注解都干了什么

@SpringBootApplication

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

进入这个注解:可以看到上面还有很多其他注解!

SpringBoot2.4.0总结,自动装配原理解析_第11张图片

@ComponentScan

这个注解在Spring中很重要 ,它对应XML配置中的元素。

作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器

@SpringBootConfiguration

作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类

我们继续进去这个注解查看

SpringBoot2.4.0总结,自动装配原理解析_第12张图片

继续进去查看

SpringBoot2.4.0总结,自动装配原理解析_第13张图片

这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件

里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!

我们回到 SpringBootApplication 注解中继续看。

@EnableAutoConfiguration

作用:开启自动配置功能

以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置

@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效

SpringBoot2.4.0总结,自动装配原理解析_第14张图片

点进注解接续查看:

@AutoConfigurationPackage

作用:自动配置包

SpringBoot2.4.0总结,自动装配原理解析_第15张图片

@import(AutoConfigurationPackages.Registrar.class)

作用:Spring底层注解,给容器中导入一个组件

Registrar 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器

这个分析完了,退到上一步,继续看

@Import(AutoConfigurationImportSelector.class)

作用:同上

AutoConfigurationImportSelector作用:自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:

  1. 这个类中有一个这样的方法

SpringBoot2.4.0总结,自动装配原理解析_第16张图片

  1. 这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法

SpringBoot2.4.0总结,自动装配原理解析_第17张图片

  1. 我们继续点击查看 loadSpringFactories() 方法

SpringBoot2.4.0总结,自动装配原理解析_第18张图片

SpringBoot2.4.0总结,自动装配原理解析_第19张图片

  1. 发现一个多次出现的文件:spring.factories,全局搜索它

spring.factories

我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!

SpringBoot2.4.0总结,自动装配原理解析_第20张图片

我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration

SpringBoot2.4.0总结,自动装配原理解析_第21张图片

可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。

结论

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作
  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中
  4. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件
  5. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作
SpringApplication

SpringBoot2.4.0总结,自动装配原理解析_第22张图片

SpringApplication.run分析

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行

SpringApplication的实例化

这个类主要做了以下四件事情:

  1. 推断应用的类型是普通的项目还是Web项目

  2. 查找并加载所有可用初始化器 , 设置到initializers属性中

  3. 找出所有的应用程序监听器,设置到listeners属性中

  4. 推断并设置main方法的定义类,找到运行的主类

查看构造器:

SpringBoot2.4.0总结,自动装配原理解析_第23张图片

run方法流程分析

SpringBoot2.4.0总结,自动装配原理解析_第24张图片

yaml语法学习

配置文件

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties

    • 语法结构 :key=value
  • application.yml

    • 语法结构 :key:空格 value

**配置文件的作用 :**修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;

比如我们可以在配置文件中修改Tomcat 默认启动的端口号!测试一下!

image-20201204104826070

yaml概述

YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)

这种语言以数据作为中心,而不是以标记语言为重点!

以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml

传统xml配置:

<server>
    <port>8081<port>
server>

yaml配置:

server:
  port: 8080
yaml基础语法

说明:语法要求严格!

  • 空格不能省略
  • 以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。
  • 属性和值的大小写都是十分敏感的。

字面量:普通的值 [ 数字,布尔值,字符串 ]

字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号

key: value

注意:

  • “ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;

    name: "Chen \n HYu"
    
    输出结果:
    Chen
    HYu
    
  • ’ ’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

    name: 'Chen \n HYu'
    
    输出结果:
    Chen \n HYu
    

对象、Map(键值对)

#对象、Map格式
k: 
  v1:
  v2:

在下一行来写对象的属性和值得关系,注意缩进;比如:

student:
 name: chy
 age: 24

行内写法

student: {name: chy,age: 24}

数组( List、set )

用 - 值表示数组中的一个元素,比如:

pets:
 - cat
 - dog
 - pig

行内写法

pets: [cat,dog,pig]

注入配置文件

yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!

yaml注入配置文件
  1. 新建一个SpringBoot项目,项目名为springboot-02-config 并导入Web模块,SpringBoot就会默认将我们的需要的模块自动配置好

  2. 在项目中的resources目录下新建一个文件 application.yml

  3. 编写一个实体类 Dog

@Data
@NoArgsConstructor
@AllArgsConstructor
@Component  // 注册bean到容器中
public class Dog {
    private String name;
    private Integer age; 
}
  1. 原来是如何给bean注入属性值的? @Value
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component //注册bean
public class Dog {
   @Value("旺财")
   private String name;
   @Value("3")
   private Integer age;
}
  1. 在SpringBoot的测试类下做测试
@SpringBootTest
class Springboot02ConfigApplicationTests {
    @Autowired
    private Dog dog;
    
    @Test
    void contextLoads() {
        System.out.println(dog);
    }
}

结果成功输出,@Value 注入成功

SpringBoot2.4.0总结,自动装配原理解析_第25张图片

  1. 我们再编写一个复杂一点的实体类Person
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String, Object> maps;
    private List<Object> lists;
    private Dog dog;
}
  1. 现在来使用yaml配置的方式进行注入,我们编写一个yaml配置
person:
  name: chy
  age: 24
  happy: true
  birth: 1996/11/20
  maps: {k1: v1,k2: v2}
  lists:
   - code
   - girl
   - music
  dog:
    name: 旺财
    age: 1
  1. 来注入到我们的类中
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component //注册bean
/*
    @ConfigurationProperties作用:
    将配置文件中配置的每一个属性的值,映射到这个组件中;
    告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
    参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}
  1. 去测试类中测试一下
@SpringBootTest
class DemoApplicationTests {

    @Autowired
    Person person; // 将person自动注入进来

    @Test
    public void contextLoads() {
        System.out.println(person); // 打印person信息
    }
}

结果:所有值全部注入成功!

image-20201204111921531

加载指定的配置文件

@PropertySource :加载指定的配置文件

@ConfigurationProperties:默认从全局配置文件中获取值;

  1. resources目录下新建一个person.properties文件
name=chy
  1. 在我们的代码中指定加载person.properties文件
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
// javaConfig 绑定我们配置文件的值,可以采取这些方式!
// 加载指定的配置文件
@PropertySource(value = "classpath:person.properties")
/**
 * @ConfigurationProperties作用:
 * 将配置文件中配置的每一个属性的值,映射到这个组件中;
 * 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
 * 参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
 */
// @ConfigurationProperties(prefix = "person")
public class Person {

    // SPEL表达式取出配置文件的值
    @Value("${name}")
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String, Object> maps;
    private List<Object> lists;
    private Dog dog;
}
  1. 再次输出测试一下:指定配置文件绑定成功!

image-20201204112544688

配置文件占位符

配置文件还可以编写占位符生成随机数

person:
 name: chy${random.uuid} # 随机uuid
 age: ${random.int} # 随机int
 happy: true
 birth: 1996/11/20
 maps: {k1: v1,k2: v2}
 lists:
   - code
   - girl
   - music
 dog:
   name: ${person.hello:other}_旺财
   age: 1

测试一下结果:

image-20201204113027914

对比小结

@Value这个使用起来并不友好!我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法) 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持
  1. @ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

  2. 松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和实体类中属性lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下

  3. JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 Date 和 Calendar 对象是否在当前时间之前  
@Future     验证 Date 和 Calendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

.......等等
除此以外,我们还可以自定义一些数据校验规则
  1. 复杂类型封装,yml中可以封装对象 , 使用value就不支持

结论:

配置yml和配置properties都可以获取到值 , 强烈推荐 yml

如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value

如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties

多环境切换

profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境

多配置文件

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本

例如:

application-test.properties代表测试环境配置

server.port=8081

application-dev.properties代表开发环境配置

server.port=8082

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

我们需要通过一个配置来选择需要激活的环境:

# 比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
# 我们启动SpringBoot,就可以看到已经切换到dev下的配置了
spring.profiles.active=dev

测试启动一下:

SpringBoot2.4.0总结,自动装配原理解析_第26张图片

yaml的多文档块

和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件,更加方便了 !

server:
 port: 8081
#选择要激活那个环境块
spring:
 profiles:
   active: prod

---
server:
 port: 8082
# springboot 2.4.x以上版本的配置环境的名称
spring:
 config:
   activate:
     on-profile: dev 

---
server:
 port: 8083
# springboot 2.4.x以下版本的配置环境的名称
spring:
 profiles: prod  

测试启动一下:

SpringBoot2.4.0总结,自动装配原理解析_第27张图片

注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!

静态资源处理

静态资源映射规则

SpringBoot中,SpringMVC的web配置都在 WebMvcAutoConfiguration 这个配置类里面

我们可以去看看 WebMvcAutoConfigurationAdapter 中有很多配置方法;

有一个方法:addResourceHandlers() 添加资源处理

SpringBoot2.4.0总结,自动装配原理解析_第28张图片

读一下源代码:比如所有的 /webjars/** , 都需要去 classpath:/META-INF/resources/webjars/ 找对应的资源

第二种静态资源映射规则

我们去找getStaticLocations()发现第二种映射规则 :/** , 访问当前的项目任意资源,它会去找 WebProperties 这个类,我们可以点进去看一下分析:

SpringBoot2.4.0总结,自动装配原理解析_第29张图片

WebProperties 可以设置和我们静态资源有关的参数;这里面指向了它会去寻找资源的文件夹,即上面数组的内容。

所以得出结论,以下四个目录存放的静态资源可以被我们识别:

"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"

我们可以在resources根目录下新建对应的文件夹,都可以存放我们的静态文件;

比如我们访问 http://localhost:8080/1.js , 他就会去这些文件夹中寻找对应的静态资源文件

什么是webjars

Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即可。

使用SpringBoot需要使用Webjars,我们可以去搜索一下:

网站:https://www.webjars.org

要使用jQuery,我们只要要引入jQuery对应版本的pom依赖即可!

<dependency>
    <groupId>org.webjarsgroupId>
    <artifactId>jqueryartifactId>
    <version>3.4.1version>
dependency>

导入完毕,查看webjars目录结构,并访问Jquery.js文件!

SpringBoot2.4.0总结,自动装配原理解析_第30张图片

访问:只要是静态资源,SpringBoot就会去对应的路径寻找资源,我们这里访问:http://localhost:8080/webjars/jquery/3.4.1/jquery.js

SpringBoot2.4.0总结,自动装配原理解析_第31张图片

自定义静态资源路径

我们也可以自己通过配置文件来指定一下,哪些文件夹是需要我们放静态资源文件的,在application.properties中配置

spring.web.resources.static-locations=classpath:/coding/,classpath:/chy/

一旦自己定义了静态文件夹的路径,原来的自动配置就都会失效了!

首页处理

静态资源文件夹说完后,我们继续向下看源码!可以看到一个欢迎页的映射,就是我们的首页!

SpringBoot2.4.0总结,自动装配原理解析_第32张图片

点击getWelcomePage()继续看

SpringBoot2.4.0总结,自动装配原理解析_第33张图片

欢迎页,静态资源文件夹下的所有 index.html 页面;被 /** 映射。

比如我访问 http://localhost:8080/ ,就会找静态资源文件夹下的 index.html

新建一个 index.html ,在我们上面的3个目录中任意一个,然后访问测试 http://localhost:8080/ 看结果!

SpringBoot2.4.0总结,自动装配原理解析_第34张图片

Thymeleaf

模板引擎

前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等

jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的

SpringBoot推荐你可以来使用模板引擎:

模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多

模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。

首先,我们来看SpringBoot里边怎么用。

引入Thymeleaf

找到对应的pom.xml引入依赖


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
Thymeleaf分析

我们首先得按照SpringBoot的自动配置原理看一下我们这个Thymeleaf的自动配置规则,在按照那个规则,我们进行使用。

我们去找一下Thymeleaf的自动配置类:ThymeleafProperties

SpringBoot2.4.0总结,自动装配原理解析_第35张图片

我们可以在其中看到默认的前缀和后缀

我们只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了

使用thymeleaf什么都不需要配置,只需要将他放在指定的文件夹下即可

测试

  1. 新建一个Springboot项目,项目名为springboot-03-web,并导入Web模块,Thymeleaf模块
  2. 编写一个TestController
@Controller
public class TestController {

    @RequestMapping("/test")
    public String test() {
        // classpath:/templates/test.html
        return "test";
    }
}
  1. 编写一个测试页面 test.html 放在 templates 目录下

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>测试页面h1>
body>
html>
  1. 启动项目请求测试 http://localhost:8080/test

SpringBoot2.4.0总结,自动装配原理解析_第36张图片

Thymeleaf语法学习

要学习语法,还是参考官网文档最为准确,我们找到对应的版本看一下;

Thymeleaf 官网:https://www.thymeleaf.org/ , 简单看一下官网!我们去下载Thymeleaf的官方文档

我们做个最简单的练习 :我们需要查出一些数据,在页面中展示

  1. TestController中修改测试请求,增加数据传输
@RequestMapping("/test")
public String test(Model model) {
    // 存入数据
    model.addAttribute("msg","Hello,Thymeleaf");
    // classpath:/templates/test.html
    return "test";
}
  1. 要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。

    我们可以去官方文档的#3中看一下命名空间拿来过来:

<html lang="en" xmlns:th="http://www.thymeleaf.org">
  1. 去编写下前端页面

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf学习title>
head>
<body>

<h1>测试页面h1>

<div th:text="${msg}">div>

body>
html>
  1. 启动测试

SpringBoot2.4.0总结,自动装配原理解析_第37张图片

  1. 新增一个请求
@RequestMapping("/test2")
public String test2(Map<String,Object> map){
    //存入数据
    map.put("msg","

Hello

"
); map.put("users", Arrays.asList("chy","ChenHYu")); //classpath:/templates/test.html return "test"; }
  1. test.html页面取出数据

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf学习title>
head>
<body>

<h1>测试页面h1>

<div th:text="${msg}">div>

<div th:utext="${msg}">div>



<h4 th:each="user :${users}" th:text="${user}">h4>

<h4 th:each="user:${users}">[[${user}]]h4>
    
body>
html>
  1. 启动项目测试!

SpringBoot2.4.0总结,自动装配原理解析_第38张图片

MVC自动配置原理

官网阅读

途径一:源码分析,途径二:官方文档

地址 :https://docs.spring.io/spring-boot/docs/2.4.0/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration

SpringBoot2.4.0总结,自动装配原理解析_第39张图片

以下是翻译:

SpringBoot2.4.0总结,自动装配原理解析_第40张图片

ContentNegotiatingViewResolver 内容协商视图解析器

自动配置了ViewResolver,就是我们之前学习的SpringMVC的视图解析器

即根据方法的返回值取得视图对象(View),然后由视图对象决定如何渲染(转发,重定向)

去看看源码:找到 WebMvcAutoConfiguration , 然后搜索ContentNegotiatingViewResolver。找到如下方法!

SpringBoot2.4.0总结,自动装配原理解析_第41张图片

进入ContentNegotiatingViewResolver这类看看,找到对应的解析视图的代码resolveViewName()

SpringBoot2.4.0总结,自动装配原理解析_第42张图片

继续进入getCandidateViews()看看,是如何获得候选的视图的呢?

SpringBoot2.4.0总结,自动装配原理解析_第43张图片

所以得出结论:ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的

再去研究下他的组合逻辑,看到有个属性viewResolvers,看看它是在哪里进行赋值的

SpringBoot2.4.0总结,自动装配原理解析_第44张图片

既然它是在容器中去找视图解析器,我们是否可以猜想,我们就可以去实现一个视图解析器了呢?

我们可以自己给容器中去添加一个视图解析器,这个类就会帮我们自动的将它组合进来,我们去实现一下

  1. 在我们的主程序中的config包中去写一个视图解析器MyMvcConfig
@Configuration
public class MyMvcConfig {
    @Bean
    public ViewResolver myViewResolver() {
        return new MyViewResolver();
    }

    // 我们写一个静态内部类,视图解析器就需要实现ViewResolver接口
    // ViewResolver 实现了视图解析器接口的类,我们就可以把它看作视图解析器
    public static class MyViewResolver implements ViewResolver {
        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}
  1. 怎么看我们自己写的视图解析器有没有起作用呢?

我们给 DispatcherServlet 中的 doDispatch()方法 加个断点进行调试一下,因为所有的请求都会走到这个方法中

image-20201205110930130

  1. 启动项目,然后随便访问一个页面http://localhost:8080/,看一下Debug信息

找到this中的视图解析器viewResolvers

SpringBoot2.4.0总结,自动装配原理解析_第45张图片

点进去就可以看到我们自己定义的就在这里了

image-20201205111358441

所以说,如果想要使用自己定制化的东西,只需要给容器中添加这个组件就好了,剩下的事情SpringBoot就会帮我们做了

转化器和格式化器

继续在 WebMvcAutoConfiguration 中, 然后搜索FormattingConversionService。找到如下方法!

SpringBoot2.4.0总结,自动装配原理解析_第46张图片

点进去getFormat()

image-20201205112403035

SpringBoot2.4.0总结,自动装配原理解析_第47张图片

SpringBoot2.4.0总结,自动装配原理解析_第48张图片

可以看到在我们的Properties文件中,我们可以进行自动配置它!

如果配置了自己的格式化方式,就会注册到Bean中生效,我们可以在配置文件中配置日期格式化的规则:

image-20201205112706547

修改Springboot的默认配置

扩展使用SpringMVC 官方文档如下:

SpringBoot2.4.0总结,自动装配原理解析_第49张图片

意思我们要做的就是编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,还不能标注@EnableWebMvc

//应为类型要求为WebMvcConfigurer,所以我们实现其接口
//可以使用自定义类扩展MVC的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer{
    @Bean
    public ViewResolver myViewResolver() {
        return new MyViewResolver();
    }

    // 我们写一个静态内部类,视图解析器就需要实现ViewResolver接口
    // ViewResolver 实现了视图解析器接口的类,我们就可以把它看作视图解析器
    public static class MyViewResolver implements ViewResolver {
        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 浏览器发送/chy , 就会跳转到test页面;
        registry.addViewController("/chy").setViewName("test");
    }
}

启动项目,去浏览器访问一下

SpringBoot2.4.0总结,自动装配原理解析_第50张图片

所以说,我们要扩展SpringMVC,官方就推荐我们这么去使用,既保留SpringBoot所有的自动配置,也能用我们扩展的配置!

全面接管SpringMVC

官方文档:

If you want to take complete control of Spring MVC
you can add your own @Configuration annotated with @EnableWebMvc.

全面接管即:SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己去配置

只需在我们的配置类中要加一个@EnableWebMvc

如果我们全面接管了SpringMVC了,我们之前SpringBoot给我们配置的静态资源映射一定会无效,我们可以去测试一下

不加注解之前,访问首页:

SpringBoot2.4.0总结,自动装配原理解析_第51张图片

给配置类加上注解:@EnableWebMvc

SpringBoot2.4.0总结,自动装配原理解析_第52张图片

发现所有的SpringMVC自动配置都失效了!回归到了最初的样子

当然,我们开发中,不推荐使用全面接管SpringMVC

思考问题

为什么加了一个注解,自动配置就失效了

我们看下源码:

  1. 点进@EnableWebMvc查看

SpringBoot2.4.0总结,自动装配原理解析_第53张图片

  1. 这里发现它是导入了一个类,继续点进DelegatingWebMvcConfiguration查看

image-20201205115151579

  1. 回顾一下Webmvc自动配置类WebMvcAutoConfiguration

SpringBoot2.4.0总结,自动装配原理解析_第54张图片

页面国际化

准备工作

先在IDEA中统一设置properties的编码问题

SpringBoot2.4.0总结,自动装配原理解析_第55张图片

配置文件编写
  1. 我们在resources资源文件下新建一个i18n目录,存放国际化配置文件
  2. 建立一个login.properties文件,还有一个login_zh_CN.properties,发现IDEA自动识别了我们要做国际化操作,文件夹变了

SpringBoot2.4.0总结,自动装配原理解析_第56张图片

  1. 我们可以在这上面去新建一个文件

SpringBoot2.4.0总结,自动装配原理解析_第57张图片

​ 弹出如下页面:我们再添加一个英文的

SpringBoot2.4.0总结,自动装配原理解析_第58张图片

  1. 接下来,编写配置,我们可以看到idea下面有另外一个视图

SpringBoot2.4.0总结,自动装配原理解析_第59张图片

​ 点击进入

SpringBoot2.4.0总结,自动装配原理解析_第60张图片

添加相关信息即可

SpringBoot2.4.0总结,自动装配原理解析_第61张图片

然后去查看我们的配置文件

login.properties :默认

login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

login_en_US.properties:英文

login.btn=Sign in
login.password=Password
login.remember=Remember me
login.tip=Please Sign in
login.username=Username

login_zh_CN.properties:中文

login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
配置文件生效探究

看一下SpringBoot对国际化的自动配置 ,这里又涉及到一个类:MessageSourceAutoConfiguration

里面有一个方法,这里发现SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource

SpringBoot2.4.0总结,自动装配原理解析_第62张图片

这里绑定了MessageSourceProperties

SpringBoot2.4.0总结,自动装配原理解析_第63张图片

SpringBoot2.4.0总结,自动装配原理解析_第64张图片

我们真实 的情况是放在了i18n目录下,所以我们要去springboot配置文件配置这个messages的路径

# 我们的配置文件的真实文件
spring.messages.basename=i18n.login
配置页面国际化值

去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{…}。我们去index.html页面测试下:


<html lang="en" xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>Signin Template for Bootstraptitle>
		
		<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
		
		<link th:href="@{/css/signin.css}" rel="stylesheet">
	head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">h1>
			<input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
			<input type="password" class="form-control" th:placeholder="#{login.password}" required="">
			<div class="checkbox mb-3">
				<label>
          <input type="checkbox" value="remember-me" th:text="#{login.remember}"> [[ #{login.remember} ]]
        label>
			div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">button>
			<p class="mt-5 mb-3 text-muted">© 2017-2018p>
			<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文a>
			<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">Englisha>
		form>

	body>

html>

去启动项目,访问一下,发现已经自动识别为中文的了

SpringBoot2.4.0总结,自动装配原理解析_第65张图片

配置国际化解析

在Spring中有一个国际化的Locale (区域信息对象),里面有一个叫做LocaleResolver (获取区域信息对象)的解析器!

我们去我们webmvc自动配置文件WebMvcAutoConfiguration寻找一下,看到SpringBoot默认配置:

SpringBoot2.4.0总结,自动装配原理解析_第66张图片

AcceptHeaderLocaleResolver 这个类中有一个resolveLocale()方法

SpringBoot2.4.0总结,自动装配原理解析_第67张图片

我们去自己写一个自己的LocaleResolver,可以在链接上携带区域信息

  1. 修改一下前端页面的跳转连接
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">Englisha>
  1. config包下,写一个处理的组件类MyLocaleResolver
// 可以在链接上携带区域信息
public class MyLocaleResolver implements LocaleResolver {

    // 解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        // 获取请求中的语言参数
        String language = request.getParameter("l");

        Locale locale = Locale.getDefault(); // 如果没有就使用默认的
        // 如果请求的连接携带了国际化的参数
        if (!StringUtils.isEmpty(language)) {
            // zh_CN
            String[] split = language.split("_");
            // 国家,地区
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

为了让区域化信息能够生效,需要再配置一下这个组件,在我们自己的MvcConofig下添加bean

// 应为类型要求为WebMvcConfigurer,所以我们实现其接口
// 可以使用自定义类扩展MVC的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer{

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("index.html").setViewName("index");
    }

    // 自定义的国际化组件就生效了!
    @Bean
    public LocaleResolver localeResolver() {
        return new MyLocaleResolver();
    }
}

启动项目,测试一下

SpringBoot2.4.0总结,自动装配原理解析_第68张图片

点击English

SpringBoot2.4.0总结,自动装配原理解析_第69张图片

整合JDBC

Spring Data简介

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。

Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。

Sping Data 官网:https://spring.io/projects/spring-data

数据库相关的启动器 :可以参考官方文档:

https://docs.spring.io/spring-boot/docs/2.4.0/reference/htmlsingle/#using-boot-starter

创建项目测试
  1. 新建一个项目:springboot-04-data ,在pom.xml引入相应的模块!

<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.4.0version>
        <relativePath/> 
    parent>
    <groupId>com.chygroupId>
    <artifactId>springboot-04-dataartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>springboot-04-dataname>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jdbcartifactId>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>runtimescope>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>
  1. 编写yaml配置文件连接数据库:
spring:
  datasource:
    # Mysql 5版本为 com.mysql.jdbc.Driver
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: yourusername
    password: yourpassword
    # ?serverTimezone=UTC解决时区的报错(Mysql8以上版本要设置此参数)
    url: jdbc:mysql://localhost:3306/ssmbuild?serverTimezone=UTC
  1. 配置完这些东西后,就可以直接去使用了,因为SpringBoot已经默认帮我们进行了自动配置,去测试类测试一下
@SpringBootTest
class Springboot04DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下默认的数据源 class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());
        // 获得数据库连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        // 关闭连接
        connection.close();
    }
}

结果:

SpringBoot2.4.0总结,自动装配原理解析_第70张图片

我们可以看到他默认给我们配置的数据源为 : class com.zaxxer.hikari.HikariDataSource , 我们并没有手动配置

我们来全局搜索一下,找到数据源的所有自动配置都在 :DataSourceAutoConfiguration

SpringBoot2.4.0总结,自动装配原理解析_第71张图片

这里导入的类都在 DataSourceConfiguration 配置类下,可以看出 Spring Boot 2.4.0 默认使用HikariDataSource 数据源,而以前版本,如 Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源

HikariDataSource号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀

可以使用 spring.datasource.type 指定自定义的数据源类型,值为要使用的连接池实现的完全限定名

JDBCTemplate
  1. 有了数据源(com.zaxxer.hikari.HikariDataSource),然后可以拿到数据库连接(java.sql.Connection),有了连接,就可以使用原生的 JDBC 语句来操作数据库

  2. 即使不使用第三方第数据库操作框架,如 MyBatis等,Spring 本身也对原生的JDBC 做了轻量级的封装,即JdbcTemplate

  3. 数据库操作的所有 CRUD 方法都在 JdbcTemplate 中

  4. Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用

  5. JdbcTemplate 的自动配置是依赖 org.springframework.boot.autoconfigure.jdbc 包下的 JdbcTemplateConfiguration 类

JdbcTemplate主要提供以下几类方法:

  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句
  • query方法及queryForXXX方法:用于执行查询相关语句
  • call方法:用于执行存储过程、函数相关语句

测试

编写一个JDBCController,注入 jdbcTemplate,编写测试方法进行访问测试

@RestController
public class JDBCController {
	
    /**
     * Spring Boot 默认提供了数据源,默认提供了 org.springframework.jdbc.core.JdbcTemplate
     * JdbcTemplate 中会自己注入数据源,用于简化 JDBC操作
     * 还能避免一些常见的错误,使用起来也不用再自己来关闭数据库连接
     */
    @Autowired
    private JdbcTemplate jdbcTemplate;

    // 查询数据库的所有信息
    @GetMapping("/userList")
    public List<Map<String, Object>> userList() {
        String sql = "select * from books";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }

    @GetMapping("/addUser")
    public String addUser() {
        String sql = "insert into ssmbuild.books(bookID,bookName,bookCounts,detail) values (4,'C++',2,'全世界最好的语言C++')";
        jdbcTemplate.update(sql);
        return "add-ok";
    }

    @GetMapping("/updateUser/{id}")
    public String updateUser(@PathVariable("id") Integer id,String bookName,Integer bookCounts) {
        String sql = "update ssmbuild.books set bookName=?,bookCounts=? where bookID=?";
        // 封装
        bookName = "PHP";
        bookCounts = 0;
        jdbcTemplate.update(sql,id,bookName,bookCounts);
        return "update-ok";
    }

    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable("id") Integer id) {
        String sql = "delete from ssmbuild.books where bookID=?";
        jdbcTemplate.update(sql,id);
        return "delete-ok";
    }
}

测试结果正常,这里就不一一截图

整合Druid

Druid简介

Java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,又不得不使用数据库连接池。

Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。

Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。

Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源,我们来重点介绍 Spring Boot 如何集成 Druid 数据源,如何实现数据库监控。

Github地址:https://github.com/alibaba/druid/

配置数据源
  1. 在上次的项目中添加 Druid 数据源依赖

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.2.3version>
dependency>
  1. 切换数据源;之前已经说过 Spring Boot 2.0 以上默认使用 com.zaxxer.hikari.HikariDataSource 数据源,但可以通过 spring.datasource.type 指定数据源。
spring:
  datasource:
    # Mysql 5版本为 com.mysql.jdbc.Driver
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: yourusername
    password: yourpassword
    # ?serverTimezone=UTC解决时区的报错(Mysql8以上版本要设置此参数)
    url: jdbc:mysql://localhost:3306/ssmbuild?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    # 自定义数据源
    type: com.alibaba.druid.pool.DruidDataSource
  1. 数据源切换之后,在测试类中注入 DataSource,然后获取到它,查看测试结果是否成功切换

SpringBoot2.4.0总结,自动装配原理解析_第72张图片

  1. 设置数据源连接初始化大小、最大连接数、等待时间、最小连接数 等设置项,可以查看源码
spring:
  datasource:
    # Mysql 5版本为 com.mysql.jdbc.Driver
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: yourusername
    password: yourpassword
    # ?serverTimezone=UTC解决时区的报错(Mysql8以上版本要设置此参数)
    url: jdbc:mysql://localhost:3306/ssmbuild?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    # 自定义数据源
    type: com.alibaba.druid.pool.DruidDataSource
    # Spring Boot 默认是不注入这些属性值的,需要自己绑定
    # druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    # 配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    # 如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    # 则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  1. 导入log4j的依赖

<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>
  1. 现在需要我们自己为 DruidDataSource 绑定全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了,我们需要自己添加 DruidDataSource 组件到容器中,并绑定属性,新建一个config包,并创建DruidConfig
@Configuration
public class DruidConfig {
    /*
       将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
}
  1. 去测试类中测试一下
@SpringBootTest
class Springboot04DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下默认的数据源 class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());
        // 获得数据库连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        DruidDataSource druidDataSource = (DruidDataSource) dataSource;
        System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
        System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
        // 关闭
        connection.close();
    }
}

测试结果 :可见配置参数已经生效

SpringBoot2.4.0总结,自动装配原理解析_第73张图片

配置Druid数据源监控

Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。

在我们的DruidConfig配置

// 配置 Druid 监控管理后台的Servlet;
// 因为Springboot 内置了 servlet容器, 所以没有web.xml,替代方法:ServletRegistrationBean
@Bean
public ServletRegistrationBean resourceServlet() {
    ServletRegistrationBean<ResourceServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
    /*
      这些参数可以在 com.alibaba.druid.support.http.StatViewServlet的父类
      com.alibaba.druid.support.http.ResourceServlet 中找到
    */
    Map<String, String> initParameters = new HashMap<>();
    // 后台需要有人登陆,账号密码配置
    initParameters.put("loginUsername","admin");
    initParameters.put("loginPassword","123456");

    // 后台允许谁可以访问
    // initParams.put("allow", "localhost"):表示只有本机可以访问
    // initParams.put("allow", ""):为空或者为null时,表示允许所有访问
    initParameters.put("allow","");

    // deny:Druid 后台拒绝谁访问

    // 设置初始化参数
    bean.setInitParameters(initParameters);
    return bean;
    
    // 配置 Druid 监控 之  web 监控的 filter
    @Bean
    public FilterRegistrationBean webStatFilter() {
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        // WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
        bean.setFilter(new WebStatFilter());

        Map<String, String> initParameters = new HashMap<>();
        //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
        initParameters.put("exclusions","*.js,*.css,/druid/*");
		
        bean.setInitParameters(initParameters);
        
        // "/*" 表示过滤所有请求
        bean.setUrlPatterns(Arrays.asList("/*"));
        return bean;
    }
}

配置完毕后,我们可以选择访问 :http://localhost:8080/druid

我们先随便输入一个用户名和密码进行登录,结果:

SpringBoot2.4.0总结,自动装配原理解析_第74张图片

由于我们在我们的配置类里配置了固定后台登录的用户名和密码,所以显示报错

接下来输入正确的,点击Sign in

SpringBoot2.4.0总结,自动装配原理解析_第75张图片

成功,之后我们随便测试一个之前写过的接口http://localhost:8080/userList,发现已经被Druid监控成功:

SpringBoot2.4.0总结,自动装配原理解析_第76张图片

整合Mybatis

官方文档:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

Maven仓库地址:https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter/2.1.3

SpringBoot2.4.0总结,自动装配原理解析_第77张图片

整合测试
  1. 在上次的项目中导入 MyBatis 所需要的依赖

<dependency>
    <groupId>org.mybatis.spring.bootgroupId>
    <artifactId>mybatis-spring-boot-starterartifactId>
    <version>2.1.3version>
dependency>
  1. 配置数据库连接信息(不变)
  2. 创建实体类Book
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {

    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;
}
  1. 创建mapper包以及对应的Mapper接口BookMapper
// 这个注解表示了这是一个mybatis的mapper类
@Mapper
@Repository
public interface BookMapper {
	
    // 获取所有书籍信息
    List<Book> queryBookList();
	
    // 通过id获取书籍
    Book queryBookById(int id);
	
    // 增加书籍
    int addBook(Book book);
	
    // 根据id更新书籍
    int updateBook(Book book);
	
    // 根据id删除书籍
    int deleteBook(int id);
}
  1. resources/mybatis/mapper目录下创建对应的Mapper映射文件BookMapper.xml



<mapper namespace="com.chy.mapper.BookMapper">
    
    <select id="queryBookList" resultType="Book">
        select * from books
    select>

    <select id="queryBookById" resultType="Book">
        select * from books where bookID = #{id}
    select>

    <insert id="addBook" parameterType="Book">
        insert into books(bookID,bookName,bookCounts,detail) values (#{bookID},#{bookName},#{bookCounts},#{detail})
    insert>

    <update id="updateBook" parameterType="Book">
        update books set bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail} where bookID = #{bookID}
    update>

    <delete id="deleteBook" parameterType="int">
        delete from books where bookID = #{id}
    delete>
mapper>
  1. 去springboot配置文件中配置mybatis的配置信息
# 整合mybatis
mybatis:
  type-aliases-package: com.chy.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  1. 编写对应的BookController进行测试
@RestController
public class BookController {

    @Autowired
    private BookMapper bookMapper;

    @GetMapping("/queryBookList")
    public List<Book> queryBookList() {
        return bookMapper.queryBookList();
    }

    @GetMapping("/queryBookById")
    public Book queryBookById() {
        return bookMapper.queryBookById(2);
    }

    @GetMapping("/addBook")
    public String addBook() {
        bookMapper.addBook(new Book(4,"C++",4,"守护全世界最难的语言"));
        return "ok";
    }

    @GetMapping("/updateBook")
    public String updateBook() {
        bookMapper.updateBook(new Book(4,"PHP",3,"守护语言"));
        return "ok";
    }

    @GetMapping("/deleteBook")
    public String deleteBook() {
        bookMapper.deleteBook(4);
        return "ok";
    }
}
  1. 启动项目进行测试,结果测试均正常,这里就不一一截图

整合SpringSecurity

文章地址:

https://blog.csdn.net/ChenHYu1120/article/details/110870903

你可能感兴趣的:(Spring,spring,spring,boot,java)