狂神说——SpringBoot学习

spring官网
SpringBoot官网
spring-security版本下载
狂神官网学习 也可以搜索B站 (狂神说)
学习网站:https://www.bilibili.com/video/BV1PE411i7CV?p=1

SpringBoot

Springboot简介

回顾什么是Spring

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

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

Spring是如何简化Java开发的

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

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

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

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

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

什么是SpringBoot

学过 javaweb 的同学就知道,开发一个web应用,从最初开始接触Servlet结合Tomcat, 跑出一个Hello Wolrld程序,是要经历特别多的步骤;后来就用了框架Struts,再后来是SpringMVC,到了现在的SpringBoot,过一两年又会有其他web框架出现;你们有经历过框架不断的演进,然后自己开发项目所有的技术也在不断的变化、改造吗?建议都可以去经历一遍;

言归正传,什么是SpringBoot呢,就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置, you can “just run”,能迅速的开发web应用,几行代码开发一个http接口。

所有的技术框架的发展似乎都遵循了一条主线规律:从一个复杂应用场景 衍生 一种规范框架,人们只需要进行各种配置而不需要自己去实现它,这时候强大的配置功能成了优点;发展到一定程度之后,人们根据实际生产应用情况,选取其中实用功能和设计精华,重构出一些轻量级的框架;之后为了提高开发效率,嫌弃原先的各类配置过于麻烦,于是开始提倡“约定大于配置”,进而衍生出一些一站式的解决方案。

是的这就是Java企业级应用->J2EE->spring->springboot的过程。

随着 Spring 不断的发展,涉及的领域越来越多,项目整合开发需要配合各种各样的文件,慢慢变得不那么易用简单,违背了最初的理念,甚至人称配置地狱。Spring Boot 正是在这样的一个背景下被抽象出来的开发框架,目的为了让大家更容易的使用 Spring 、更容易的集成各种常用的中间件、开源软件;

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整合了所有的框架 。

Spring Boot 出生名门,从一开始就站在一个比较高的起点,又经过这几年的发展,生态足够完善,Spring Boot 已经当之无愧成为 Java 领域最热门的技术。

springboot的主要优点

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

微服务阶段:

  • JavaSE:OOP
  • mysql:持久化
  • HTML+CSS+JS+jQuery+框架:视图框架不熟练,css不好
  • javaweb:独立开发MVC三层架构的网站:原始
  • SSM:框架:简化我们的开发流程,配置也开始较为复杂
  • war:Tomcat运行
  • spring再简化:springboot-jar:内嵌Tomcat;微服务架构
  • 服务越来越多:springcloud

约定:不需要配置或者配置很少的东西,默认存在可用的东西叫好的约定

程序=数据结构+算法(集合框架)【程序猿】
程序=面向对象+框架【码农】

前端为主的MV*时代:

  • MVC(同步通信为主【易阻塞】)

      MVC 三层架构: (Model-View-Controller)  
      	 Model:数据和业务
      	 View:HTML
      	 Controller:交接
    
  • MVP(异步通信为主)

  • MVVM (异步通信为主)

      MVVM 微服务架构:Model-View-ViewModel ,ViewModel 核心)MVVM来源于MVC
      Model : 模型层,在这里表示JavaScript对象
      View : 视图层,在这里表示DOM (HTML操作的元素)
      ViewModel : 连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者在MVVM架构中,	
      			是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者;
      			ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新;
      			ViewModel 能够监听到视图的变化,并能够通知数据发生改变
    
      MVVM优点:低耦合、可复用、独立开发、可测试
      
      优点展开详细说明:
      MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处:
      1. 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
      2. 可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
      3. 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
      4. 可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
    

至此,我们就明白了,Vue.js 就是一个MVVM的实现者,他的核心就是实现了DOM监听与数据绑定

springboot常用的starter有哪些

spring-boot-starter-web   嵌入tomcat和web开发需要servlet与jsp支持
spring-boot-starter-data-jpa  数据库支持
spring-boot-starter-data-redis   redis数据库支持
spring-boot-starter-data-solr   solr支持
mybatis-spring-boot-starter   第三方的mybatis集成starter

什么是微服务?

微服务论文(英文版)
微服务论文(中文版)
微服务架构的系统是一个分布式的系统,按业务进行划分为独立的服务单元,解决单体系统的不足,同时也满足越来越复杂的业务需求。

微服务架构就是将单一程序开发成一个微服务,每个微服务运行在自己的进程中,并使用轻量级的机制通信,通常是HTTP RESTFUL API。这些服务围绕业务能力来划分,并通过自动化部署机制来独立部署。这些服务可以使用不同的编程语言,不同数据库,以保证最低限度的集中式管理。

总结起来微服务就是将一个单体架构的应用按业务划分为一个个的独立运行的程序即服务,它们之间通过HTTP协议进行通信(也可以采用消息队列来通信,如RoocketMQ,Kafaka等),可以采用不同的编程语言,使用不同的存储技术,自动化部署(如Jenkins)减少人为控制,降低出错概率。服务数量越多,管理起来越复杂,因此采用集中化管理。例如Eureka,Zookeeper等都是比较常见的服务集中化管理框架。

springboot可以自定义启动时的图标,默认为spring字样,如果想拥有自己的图标也可以在这个网站获取 springboot自定义banner图标

注解

@SpringBootApplication【springboot的配置】
	@Configuration【spring配置类】
	@Component【说明这也是spring的一个组件】

@EnableAutoConfiguration 【自动配置】
	@AutoConfigurationPackage【自动配置包】
		@Import(AutoConfigurationPackages.Registrar.class)【自动配置‘包注册’】
	@Import(AutoConfigurationImportSelector.class)  【自动导入包的核心(自动配置导入选择)】        
		List<String> configurations=getCandidateConfigurations(annotationMetadata,attributes);

SpringApplication

主入口里面的SpringApplication 类,这个类主要做了4个事情:

  1. 推断应用的类型是普通的项目还是Web项目
  2. 查找并加载所有可用初始化器。设置initializers 属性
  3. 找出所有的应用程序监听器,设置到listeners 属性中
  4. 推断并设置main方法的定义类,找到运行的主类
    在这里插入图片描述
  • application.properties:只能以键值对格式存在,书写的中文编译可能会乱码
  • application.yml:可(赋值)表示对象、数组、纯量 ,也支持函数、正则表达式等。也可以使用${xxx}表达获取前面已经定义的变量(属性)
    例如 :
    spring:
      application:
        name: springWeb
        instance-id: ${
         spring.application.name}:${
         server.port} #取自前面已定义的属性
    

yml格式的特点:

  1. 大小写敏感
  2. 使用缩进表示层级关系
  3. 缩进时不允许使用Tab键,只允许使用空格
  4. 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可. (通常采用两个空格表示一个缩进)

YAML 语言教程——阮一峰

YAML 支持的数据结构有三种。

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值
@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

接口调用优先级:

1. file:./config/
2. file:./
3. classpath:/config/
4. classpath:/

在这里插入图片描述
在这里插入图片描述

静态资源导入探究:
总结:

  1. 在springboot,我们可以使用以下方式处理静态资源

     (1)webjars: localhost:8080/webjars/
     (2)public,static,/**,resources : localhost:8080/xxx.jar
    
  2. 优先级:resource>static(默认)>public

第一个SpringBoot程序

准备工作

我们将学习如何快速的创建一个Spring Boot应用,并且实现一个简单的Http请求处理。通过这个例子对Spring Boot有一个初步的了解,并体验其结构简单、开发快速的特性。

我的环境准备跟开发工具:jdk1.8、Maven-3.6.1、SpringBoot 最新版、IDEA

创建基础项目说明

Spring官方提供了非常方便的工具让我们快速构建应用
Spring Initializr:https://start.spring.io/

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

1、打开 https://start.spring.io/
2、填写项目信息
3、点击”Generate Project“按钮生成项目;下载此项目
4、解压项目包,并用IDEA以Maven项目导入,一路下一步即可,直到项目导入完毕。
5、如果是第一次使用,可能速度会比较慢,包比较多、需要耐心等待一切就绪。

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

1、创建一个新项目
2、选择spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现
3、填写项目信息
4、选择初始化的组件(初学勾选 Web 即可)
5、填写项目路径
6、等待项目构建成功

项目结构分析

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

1、程序的主启动类
2、一个 application.properties 配置文件
3、一个 测试类
4、一个 pom.xml

pom.xml 分析

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

<!-- 父工程依赖 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- web场景启动器 -->
    <!--web依赖:tomcat,dispatcherServlet,xml...-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--spring-boot-starter:所有的springboot依赖都是使用这个开头的-->
    <!-- springboot单元测试 -->
    <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>

<build>
    <plugins>
        <!-- 打包插件 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>

<!--在工作中,很多情况下我们打包是不想执行测试用例的,可能是测试用例不完善,或是测试用例会影响数据库数据,跳过测试用例执 -->
        <!--<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
               跳过项目运行测试用例
                <skipTests>true</skipTests>
            </configuration>
        </plugin>-->
        
    </plugins>
</build>

如上所示,主要有四个部分:

  • 项目元数据:创建时候输入的Project Metadata部分,也就是Maven项目的基本元素,包括:groupId、artifactId、version、name、description等

  • parent:继承spring-boot-starter-parent的依赖管理,控制版本与打包等内容

  • dependencies:项目具体依赖,这里包含了spring-boot-starter-web用于实现HTTP接口(该依赖中包含了Spring MVC),官网对它的描述是:使用Spring MVC构建Web(包括RESTful)应用程序的入门者,使用Tomcat作为默认嵌入式容器。spring-boot-starter-test用于编写单元测试的依赖包。更多功能模块的使用将在后面逐步展开。

  • build:构建配置部分。默认使用了spring-boot-maven-plugin,配合spring-boot-starter-parent就可以把Spring Boot应用打包成JAR来直接运行。

编写一个http接口

  1. 在主程序的同级目录下,新建一个controller包,一定要在同级目录下,否则识别不到
    在这里插入图片描述
  2. 在包中新建一个HelloController类
@RestController
public class HelloController {
   

    @RequestMapping("/hello")
    public String hello() {
   
        return "Hello World";
    }
    
}
  1. 编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回;控制台输出了 Tomcat 访问的端口号!
    在这里插入图片描述简单几步,就完成了一个web接口的开发,SpringBoot就是这么简单。所以我们常用它来建立我们的微服务项目!

将项目打成jar包,点击 maven的 package

如果打包成功,则会在target目录下生成一个 jar 包
在这里插入图片描述
如果遇到以上②的错误,可以配置打包时跳过项目运行测试用例(上面有讲过的,注释掉的)

<!--在工作中,很多情况下我们打包是不想执行测试用例的可能是测试用例不完善,或是测试用例会影响数据库数据 跳过测试用例执-->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <!--跳过项目运行测试用例-->
        <skipTests>true</skipTests>
    </configuration>
</plugin>

打成了jar包后,就可以在任何地方运行了!OK
在这里插入图片描述
浏览器运行结果(上图第⑤步):
在这里插入图片描述

更改banner图标

如何更改启动时显示的字符拼成的字母,SpringBoot呢?
只需一步:到项目下的 resources 目录下新建一个banner.txt 即可。

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

02 运行原理探究

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

父依赖

pom.xml

  • spring-boot-dependencies:核心依赖在父工程中!
  • 我们在写或者引入一些Springboot依赖的时候,不需要指定版本,就因为有这些版本仓库
  1. 其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.1.RELEASE</version>
    <relativePath/> 
    <!-- lookup parent from repository -->
</parent>
  1. 点进去,发现还有一个父依赖
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.1.RELEASE</version>
</parent>
  1. 这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

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

启动器(pring-boot-starter)

  • 依赖
<dependency>        								 	
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
  • springboot-boot-starter-xxx,说白了就是Springboot的启动场景

  • 比如spring-boot-starter-web,他就会帮我们自动导入web的所有依赖

  • springboot会将所有的功能场景,都变成一个个的启动器

  • 我们要使用什么功能,就只需要找到对应的启动器就好了start

主程序

默认的主启动类

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

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

注解(@SpringBootApplication)

  • 作用:标注在某个类上说明这个类是SpringBoot的主配置
  • SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
  • 进入这个注解:可以看到上面还有很多其他注解!
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {
   @Filter(
    type = FilterType.CUSTOM,
    classes = {
   TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {
   AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
   
    // ......
}

@ComponentScan

  • 这个注解在Spring中很重要 ,它对应XML配置中的元素。
  • 作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中

@SpringBootConfiguration

  • 作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;
  • 我们继续进去这个注解查看
    // 点进去得到下面的 @Component
    @Configuration
    public @interface SpringBootConfiguration {
         }
    
    @Component
    public @interface Configuration {
         }
    
  • 这里的 @Configuration,说明这是一个spring的配置类 ,配置类就是对应Spring的xml 配置文件;
  • @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!
  • 我们回到 SpringBootApplication 注解中继续看。

@EnableAutoConfiguration

  • 开启自动配置功能

      以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;
      @EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
    

    点进注解接续查看:

  • @AutoConfigurationPackage :自动配置包

    @Import({
         Registrar.class})
    public @interface AutoConfigurationPackage {
         
    }
    
    • @import :Spring底层注解@import , 给容器中导入一个组件

    • Registrar.class 作用:自动配置包注册,将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;

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

  • @Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;

    • AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
    @Import({
         AutoConfigurationImportSelector.class}) :给容器导入组件 ;
    
    AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
    
    // 获取所有的配置 List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    

    // 获取所有的配置 List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

    - 获得候选的配置
    ```java
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
         
        // 和下面的方法对应
        //这里的getSpringFactoriesLoaderFactoryClass()方法
        //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
      List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        
      
        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;
    }
    
    //和上面的类的方法loadFactoryNames里面的第一个参数对应
    //这里的getSpringFactoriesLoaderFactoryClass()方法
    //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
         
         return EnableAutoConfiguration.class;
    }
    
    • 这个方法getCandidateConfigurations()又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法,获取所有的加载配置
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
         
        String factoryClassName = factoryClass.getName();
        //这里它又调用了 loadSpringFactories 方法
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
    
    • 我们继续点击查看 loadSpringFactories 方法

      • 项目资源:META-INF/spring.factories
      • 系统资源:META-INF/spring.factories
      • 从这些资源中配置了所有的nextElement(自动配置),分装成properties
      //将所有的资源加载到配置类中(将下面的抽离出来分析,第15行)
      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
      
      private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
             
          //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
          MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
          if (result != null) {
             
              return result;
          } else {
             
              try {
             
                  //去获取一个资源 "META-INF/spring.factories"
                  Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                  LinkedMultiValueMap result = new LinkedMultiValueMap();
                  //判断有没有更多的元素,将读取到的资源循环遍历,封装成为一个Properties
                  while(urls.hasMoreElements()) {
             
                    URL url = (URL)urls.nextElement();
                      UrlResource resource = new UrlResource(url);
                      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                      Iterator var6 = properties.entrySet().iterator();
                      while(var6.hasNext()) {
             
                          Entry<?, ?> entry = (Entry)var6.next();
                          String factoryClassName = ((String)entry.getKey()).trim();
                          String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                          int var10 = var9.length;
                          for(int var11 = 0; var11 < var10; ++var11) {
             
                              String factoryName = var9[var11];
                              result.add(factoryClassName, factoryName.trim());
                          }
                      }
                  }
                  cache.put(classLoader, result);
                  return result;
              } catch (IOException var13) {
             
                  throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
              }
          }
      }
      
      • 发现一个多次出现的文件:spring.factories,全局搜索它

spring.factories

我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
在这里插入图片描述
WebMvcAutoConfiguration

我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration
在这里插入图片描述
可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

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

工作原理总结

  1. 读取spring.properties文件
    (1)SpringBoot在启动的时候从spring-boot-autoConfigure.jar包下的的META-INF/spring.factories中获取EnableAutoConfiguration属性的值加载 自动配置类

    (2)将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;

  2. 加载XXXProperties
    根据自动配置类中指定的xxxxProperties类设置自动配置的属性值,开发者可以根据该类在yml配置文件中修改自动配置

  3. 根据@ConditionalXXX注解决定加载哪些组件
    Springboot通过该注解指定组件加入IOC容器时锁需要具备的特定条件。这个组件会在满足条件时候加入到IOC容器内
    在这里插入图片描述

结论:

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  3. 以前我们需要自动配置的东西,现在springboot帮我们做了
  4. 整合JavaEE,整体解决方案和自动配置的东西都在springboot-autoconfigure的jar包中;
  5. 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器中
  6. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并自动配置,@Configuration(javaConfig) ;
  7. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

现在大家应该大概的了解了SpringBoot的运行原理,后面我们还会深化一次!

启动 SpringApplication.run(xxx.class, args);

1、不简单的方法

我最初以为就是运行了一个main方法,没想到却开启了一个服务;

@SpringBootApplication
public class Springboot01HellowordApplication {
   

    public static void main(String[] args) {
   
       	//该方法返回一个ConfigurableApplicationContext对象
 		//参数一:应用入口的类; 参数二:命令行参数  
        SpringApplication.run(Springboot01HellowordApplication.class, args);
    }

}

SpringApplication.run分析

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

2、SpringApplication

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

  1. 推断应用的类型是普通的项目还是Web项目
  2. 查找并加载所有可用初始化器 , 设置到initializers属性中
  3. 找出所有的应用程序监听器,设置到listeners属性中
  4. 推断并设置main方法的定义类,找到运行的主类

查看构造器:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
   
    // ......
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances();
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

3、run方法流程分析(跟着源码和这幅图就可以一探究竟了!)

在这里插入图片描述

4、关于SpringBoot,谈谈关于你的理解;

  • 自动装配
  • run()
  • 全面接管SpringMVC的配置

03 yaml语法学习

配置文件

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

  • application.properties
  • 语法结构 :key=value
  • application.yaml
  • 语法结构 :key:空格 value

配置文件的作用 :修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;
比如我们可以在配置文件中修改Tomcat 默认启动的端口号!测试一下!

server:
  port: 8081

YAML

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:
      prot: 8080
     #  servlet:
    	# 原先的Tomcat工程路径在这里修改
    	# context-path: /laosong    
    

yaml基础语法

说明:语法要求严格!

  1. 空格不能省略

  2. 以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

  3. 属性和值的大小写都是十分敏感的。

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

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

    注意:

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

      比如 :name: "kuang \n shen"
      输出 :kuang 换行 shen

    • '' 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

      比如 :name: ‘kuang \n shen’
      输出 :kuang \n shen

对象、Map(键值对)

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

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

student:
    name: qinjiang
    age: 3

行内写法

student: {name: qinjiang,age: 3}

数组( List、set )

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

pets:
 - cat
 - dog
 - pig

行内写法

pets: [cat,dog,pig]

修改SpringBoot的默认端口号

配置文件中添加,端口号的参数,就可以切换端口;

server:
  port: 8082

注入配置文件

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

yaml注入配置文件

  1. 在springboot项目中的resources目录下新建一个文件 application.yaml

  2. 编写一个实体类 Dog;

    package nuc.ss.pojo;
    
    @Component  //注册bean到容器中
    public class Dog {
         
        private String name;
        private Integer age;
        
        //有参无参构造、get、set方法、toString()方法  
    }
    
  3. 思考,我们原来是如何给bean注入属性值的!@Value,给狗狗类测试一下:

    @Component //注册bean
    public class Dog {
         
        @Value("阿黄")
        private String name;
        @Value("18")
        private Integer age;
    }
    
  4. 在SpringBoot的测试类下注入狗狗输出一下;

    @SpringBootTest
    class Springboot02ConfigApplicationTests {
         
    
        @Autowired
        private Dog dog;
    
        @Test
        void contextLoads() {
         
            System.out.println(dog);
        }
    
    }
    

    结果成功输出,@Value注入成功,这是我们原来的办法对吧。
    在这里插入图片描述

  5. 我们在编写一个复杂一点的实体类:Person 类

    @Component //注册bean到容器中
    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;
        
        //有参无参构造、get、set方法、toString()方法  
    }
    
  6. 我们来使用yaml配置的方式进行注入,大家写的时候注意区别和优势,我们编写一个yaml配置!

    person:
      name: qinjiang
      age: 3
      happy: false
      birth: 2000/01/01
      maps: {
         k1: v1,k2: v2}
      lists:
       - code
       - girl
       - music
      dog:
        name: 旺财
        age: 1
    
  7. 我们刚才已经把person这个对象的所有值都写好了,我们现在来注入到我们的类中!

    /*
    @ConfigurationProperties作用:
    将配置文件中配置的每一个属性的值,映射到这个组件中;
    告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
    参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
    */
    @Component
    @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;
    
        //有参无参构造、get、set方法、toString()方法
    }
    
  8. IDEA 提示,springboot配置注解处理器没有找到,让我们看文档,我们可以查看文档,找到一个依赖!
    8.1、注解@ConfigurationProperties(prefix = "person")
    在这里插入图片描述点击 open Decumentation进入官网
    在这里插入图片描述
    8.2、在pom中导入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    
  9. 确认以上配置都OK之后,我们去测试类中测试一下:

    @SpringBootTest
    class Springboot02ConfigApplicationTests {
         
        @Autowired
        private Person person;
        @Test
        void contextLoads() {
         
            System.out.println(person);
        }
    
    }
    

结果:所有值全部注入成功!
在这里插入图片描述
yaml配置注入到实体类完全OK!

加载指定的配置文件

  • @PropertySource :加载指定的配置文件;
  • @configurationProperties:默认从全局配置文件中获取值;
  1. 我们去在resources目录下新建一个person.properties文件

    name=kuangshen
    
  2. 然后在我们的代码中指定加载person.properties文件

    @PropertySource(value = "classpath:person.properties")
    @Component //注册bean
    public class Person {
         
    
        @Value("${name}")
        private String name;
    
        ......  
    }
    
  3. 再次输出测试一下:指定配置文件绑定成功!
    在这里插入图片描述

配置文件占位符

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

person:
  name: qinjiang${random.uuid}
  age: ${random.int}
  happy: false
  birth: 2020/07/13
  maps: {
   k1: v1,k2: v2}
  lists:
    - code
    - music
    - girl
  dog:
    name: ${person.hell:hello}_旺财
    age: 3

回顾properties配置

  • 我们上面采用的yaml方法都是最简单的方式,开发中最常用的;
  • 也是springboot所推荐的!
  • 那我们来唠唠其他的实现方式,道理都是相同的;写还是那样写;配置文件除了yml还有我们之前常用的properties , 我们没有讲,我们来唠唠!

【注意】properties配置文件在写中文的时候,会有乱码 , 我们需要去IDEA中设置编码格式为UTF-8;settings–>FileEncodings 中配置;
在这里插入图片描述

对比小结

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

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

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

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

  4. 复杂类型封装,yml中可以封装对象 , 使用value就不支持

结论

配置yml和配置properties都可以获取到值 , 强烈推荐 yml;
如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;
如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫!

04 JSR303数据校验

如何使用

Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式;

1、添加validation启动器

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

2、@Email添加

@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated  //数据校验
public class Person {
   
    @Email(message="邮箱格式错误") //name必须是邮箱格式
    private String name;
}

运行结果 :default message [不是一个合法的电子邮件地址];

在这里插入图片描述
使用数据校验,可以保证数据的正确性;

常见参数:

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private in
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值