SpringBoot学习笔记整理

 

第一个springBoot程序:

 

什么是spring :?

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

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

 

spring前身的javaEE开发:  就是Java企业级应用->J2EE->spring->springboot的过程。

 

Spring是如何简化Java开发的:

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

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

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

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

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

 

什么是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 领域最热门的技术。

Spring Boot的主要优点:

  • 为所有Spring开发者更快的入门

  • 开箱即用,提供各种默认配置来简化项目配置

  • 内嵌式容器简化Web项目

  • 没有冗余代码生成和XML配置的要求

 

如何创建springBoot项目: 

创建springBoot项目方式一:

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,看看Spring Boot项目的依赖:

这个web场景启动器 是配置的是否导入依赖的 如果配置了这个starter启动器 那么就会导入相关的依赖  然后就会有一个配置类

从主程序点击@springBootApplication一直点击进去会有 找到相应的配置类  这个配置类会在一个maven jar 依赖中的一个配置文件中

这个配置文件就对应了好多maven依赖  ---> 然后对应了一个一个的配置类 

这些配置类的属性值可以使用注入的方式赋值() , 也可以使用 @value注解在配置实体类中进行赋值操作(spring) ,以前使用set方法或者构造器方式进行赋值的操作

然后现在使用的是springBoot 框架,那么这个配置的实体类就和 spring项目的 yml 配置文件绑定起来了,即:

可以在yml配置文件中给相应的配置类的属性进行赋值操作,如: server:port: 8080 

当然我们需要熟悉 yml 文件的书写格式 如 list集合 实体 map集合 等数据在这个配置文件中的书写规范 后续会提及!

 1 <!-- 父依赖 -->
 2 <parent>
 3     <groupId>org.springframework.boot</groupId>
 4     <artifactId>spring-boot-starter-parent</artifactId>
 5     <version>2.2.5.RELEASE</version>
 6     <relativePath/>
 7 </parent>
 8 
 9 <dependencies>
10     <!-- web场景启动器 -->
11     <dependency>
12         <groupId>org.springframework.boot</groupId>
13         <artifactId>spring-boot-starter-web</artifactId>
14     </dependency>
15     <!-- springboot单元测试 -->
16     <dependency>
17         <groupId>org.springframework.boot</groupId>
18         <artifactId>spring-boot-starter-test</artifactId>
19         <scope>test</scope>
20         <!-- 剔除依赖 -->
21         <exclusions>
22             <exclusion>
23                 <groupId>org.junit.vintage</groupId>
24                 <artifactId>junit-vintage-engine</artifactId>
25             </exclusion>
26         </exclusions>
27     </dependency>
28 </dependencies>
29 
30 <build>
31     <plugins>
32         <!-- 打包插件 -->
33         <plugin>
34             <groupId>org.springframework.boot</groupId>
35             <artifactId>spring-boot-maven-plugin</artifactId>
36         </plugin>
37     </plugins>
38 </build>

 

配置完后编写一个控制层,运行程序。

然后给程序进行打包 jar  点击maven的package

 

 

打包时,如果碰到问题 ,可以配置打包时 跳过项目运行测试用例

 1 <!--
 2     在工作中,很多情况下我们打包是不想执行测试用例的
 3     可能是测试用例不完事,或是测试用例会影响数据库数据
 4     跳过测试用例执
 5     -->
 6 <plugin>
 7     <groupId>org.apache.maven.plugins</groupId>
 8     <artifactId>maven-surefire-plugin</artifactId>
 9     <configuration>
10         <!--跳过项目运行测试用例-->
11         <skipTests>true</skipTests>
12     </configuration>
13 </plugin>

 

 

 

打成了jar包后,就可以在任何地方运行了!OK

 

然后我们可以设置项目启动时候的图标。

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

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

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

 

SpringBoot的自动装配原理:

 

 

 

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

pom.xml

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

1 <parent>
2     <groupId>org.springframework.boot</groupId>
3     <artifactId>spring-boot-starter-parent</artifactId>
4     <version>2.2.5.RELEASE</version>
5     <relativePath/> <!-- lookup parent from repository -->
6 </parent>

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

1 <parent>
2     <groupId>org.springframework.boot</groupId>
3     <artifactId>spring-boot-dependencies</artifactId>
4     <version>2.2.5.RELEASE</version>
5     <relativePath>../../spring-boot-dependencies</relativePath>
6 </parent>

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

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

 

启动器 spring-boot-starter

 1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-web</artifactId> 4 </dependency> 

 

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

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

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

这个启动器starter就是和上面的 spring.factories配置文件联系 配置文件中的一个一个配置好的配置类 使用@Configution注解标注的 如果没有配置 启动器 有些点击进去就会报错。

 

主启动类

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

 

注解详解,上面的图片是关系!

@SpringBootApplication

作用:标注在某个类上说明这个类是SpringBoot的主配置类 ,

SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;

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

 1 @SpringBootConfiguration
 2 @EnableAutoConfiguration
 3 @ComponentScan(
 4     excludeFilters = {@Filter(
 5     type = FilterType.CUSTOM,
 6     classes = {TypeExcludeFilter.class}
 7 ), @Filter(
 8     type = FilterType.CUSTOM,
 9     classes = {AutoConfigurationExcludeFilter.class}
10 )}
11 )
12 public @interface SpringBootApplication {
13     // ......
14 }

@ComponentScan

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

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

@SpringBootConfiguration

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

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

1 // 点进去得到下面的 @Component
2 @Configuration
3 public @interface SpringBootConfiguration {}
4 
5 @Component
6 public @interface Configuration {}

 

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

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

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

@EnableAutoConfiguration

@EnableAutoConfiguration :开启自动配置功能

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

点进注解接续查看

@AutoConfigurationPackage :自动配置包

 1 @Import({Registrar.class}) 2 public @interface AutoConfigurationPackage { 3 } 

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

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

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

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

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

 

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

1 // 获得候选的配置
2 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
3     //这里的getSpringFactoriesLoaderFactoryClass()方法
4     //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
5     List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
6     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.");
7     return configurations;

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

1 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
2     String factoryClassName = factoryClass.getName();
3     //这里它又调用了 loadSpringFactories 方法
4     return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
5 }

3、我们继续点击查看 loadSpringFactories 方法

 1 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
 2     //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
 3     MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
 4     if (result != null) {
 5         return result;
 6     } else {
 7         try {
 8             //去获取一个资源 "META-INF/spring.factories"
 9             Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
10             LinkedMultiValueMap result = new LinkedMultiValueMap();
11 
12             //将读取到的资源遍历,封装成为一个Properties
13             while(urls.hasMoreElements()) {
14                 URL url = (URL)urls.nextElement();
15                 UrlResource resource = new UrlResource(url);
16                 Properties properties = PropertiesLoaderUtils.loadProperties(resource);
17                 Iterator var6 = properties.entrySet().iterator();
18 
19                 while(var6.hasNext()) {
20                     Entry<?, ?> entry = (Entry)var6.next();
21                     String factoryClassName = ((String)entry.getKey()).trim();
22                     String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
23                     int var10 = var9.length;
24 
25                     for(int var11 = 0; var11 < var10; ++var11) {
26                         String factoryName = var9[var11];
27                         result.add(factoryClassName, factoryName.trim());
28                     }
29                 }
30             }
31 
32             cache.put(classLoader, result);
33             return result;
34         } catch (IOException var13) {
35             throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
36         }
37     }
38 }

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

spring.factories

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

 

 

WebMvcAutoConfiguration

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

 

 

@Bean 和 @Configuration 注解 在 spring.factories 中的所有配置类

可以看到这些一个个的都是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. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

后面讲解这个自动装配好的配置实体类和springBoot配置文件 yml 的联系!

 

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

1 @SpringBootApplication
2 public class SpringbootApplication {
3     public static void main(String[] args) {
4         SpringApplication.run(SpringbootApplication.class, args);
5     }
6 }

SpringApplication.run分析

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

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

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

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

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

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

查看构造器:

1 public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
2     // ......
3     this.webApplicationType = WebApplicationType.deduceFromClasspath();
4     this.setInitializers(this.getSpringFactoriesInstances();
5     this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
6     this.mainApplicationClass = this.deduceMainApplicationClass();
7 }

run方法流程分析:

 

 

yaml语法: 注意空格和缩进

配置文件

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

  • application.properties

    • 语法结构 :key=value

  • application.yml

    • 语法结构 :key:空格 value

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

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

 

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

传统xml配置:

 1 <server> 2 <port>8081<port> 3 </server> 

yaml配置:

server: 
prot: 8080


yaml基础语法

说明:语法要求严格!

1、空格不能省略

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

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

 

字符串默认不用加上双引号或者单引号

注意:

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

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

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

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

 

对象、Map(键值对)、数组( List、set )

 

 

 

 

 

 

 

 

 

 

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

原来是给bean注入属性值!@Value

 

我们来使用yaml配置的方式进行注入,大家写的时候注意区别和优势,我们编写一个yaml配置!

注意空格和缩进:

 

 

我们刚才已经把person这个对象的所有值都写好了,我们现在来注入到我们的类中!

 1 /*
 2 @ConfigurationProperties作用:
 3 将配置文件中配置的每一个属性的值,映射到这个组件中;
 4 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
 5 参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
 6 */
 7 @Component //注册bean
 8 @ConfigurationProperties(prefix = "person")
 9 public class Person {
10     private String name;
11     private Integer age;
12     private Boolean happy;
13     private Date birth;
14     private Map<String,Object> maps;
15     private List<Object> lists;
16     private Dog dog;
17 }

 

IDEA 提示,springboot配置注解处理器没有找到,让我们看文档,我们可以查看文档,找到一个依赖!

1 <!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
2 <dependency>
3   <groupId>org.springframework.boot</groupId>
4   <artifactId>spring-boot-configuration-processor</artifactId>
5   <optional>true</optional>
6 </dependency>

 

yaml配置注入到实体类完全OK!

1、将配置文件的key 值 和 属性的值设置为不一样,则结果输出为null,注入失败

2、在配置一个person2,然后将 @ConfigurationProperties(prefix = "person2") 指向我们的person2;

 

我们也可以使用不同的配置文件 自定义一个配置文件 但是在实体类上就需要使用不同的注解

 

 

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

 1 person:
 2     name: qinjiang${random.uuid} # 随机uuid
 3     age: ${random.int}  # 随机int
 4     happy: false
 5     birth: 2000/01/01
 6     maps: {k1: v1,k2: v2}
 7     lists:
 8       - code
 9       - girl
10       - music
11     dog:
12       name: ${person.hello:other}_旺财
13       age: 1

 

回顾properties配置

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

【注意】properties配置文件在写中文的时候,会有乱码 , 我们需要去IDEA中设置编码格式为UTF-8;

settings-->FileEncodings 中配置;

 

 

 

 

对比小结

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

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

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

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

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

结论:

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

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

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

 

 JSR303数据校验:

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

也是使用注解进行操作:在实体类的类上和相对于的属性上使用不同的注解完成不同的数据校验。如:

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

 

多环境切换:

1、多环境切换指的是可以配置几个不同的配置文件 properties/yml 他们可以分别放在项目里面,但是有优先级

2、然后在默认的配置文件中指定执行哪个配置文件 。 有开发版本、测试版本 等。。

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

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

 

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

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

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

 

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

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

 

但是使用yaml的格式的配置文件就更加方便了,他不用写几个配置文件,只需要使用分割线然后切换就可以了。

yaml的多文档块

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

 1 server:
 2   port: 8081
 3 #选择要激活那个环境块
 4 spring:
 5   profiles:
 6     active: prod
 7 
 8 ---
 9 server:
10   port: 8083
11 spring:
12   profiles: dev #配置环境的名称
13 
14 
15 ---
16 
17 server:
18   port: 8084
19 spring:
20   profiles: prod  #配置环境的名称

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

 

配置文件加载位置

外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!

 

 

 

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级由高到底,高优先级的配置会覆盖低优先级的配置;

SpringBoot会从这四个位置全部加载主配置文件;互补配置;

我们在最低级的配置文件中设置一个项目访问路径的配置来测试互补问题;(即高级的配置文件覆盖低级的配置文件内容,高级中没有的使用低级中的)

 

运维小技巧

指定位置加载配置文件

我们还可以通过spring.config.location来改变默认的配置文件位置

项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高

 1 jar spring-boot-config.jar --spring.config.location=F:/application.properties 

 

 

分析自动配置原理:

我们以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;

 1 //表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
 2 @Configuration 
 3 
 4 //启动指定类的ConfigurationProperties功能;
 5   //进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
 6   //并把HttpProperties加入到ioc容器中
 7 @EnableConfigurationProperties({HttpProperties.class}) 
 8 
 9 //Spring底层@Conditional注解
10   //根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
11   //这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
12 @ConditionalOnWebApplication(
13     type = Type.SERVLET
14 )
15 
16 //判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
17 @ConditionalOnClass({CharacterEncodingFilter.class})
18 
19 //判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
20   //如果不存在,判断也是成立的
21   //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
22 @ConditionalOnProperty(
23     prefix = "spring.http.encoding",
24     value = {"enabled"},
25     matchIfMissing = true
26 )
27 
28 public class HttpEncodingAutoConfiguration {
29     //他已经和SpringBoot的配置文件映射了
30     private final Encoding properties;
31     //只有一个有参构造器的情况下,参数的值就会从容器中拿
32     public HttpEncodingAutoConfiguration(HttpProperties properties) {
33         this.properties = properties.getEncoding();
34     }
35     
36     //给容器中添加一个组件,这个组件的某些值需要从properties中获取
37     @Bean
38     @ConditionalOnMissingBean //判断容器没有这个组件?
39     public CharacterEncodingFilter characterEncodingFilter() {
40         CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
41         filter.setEncoding(this.properties.getCharset().name());
42         filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
43         filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
44         return filter;
45     }
46     //。。。。。。。
47 }

 

一句话总结 :根据当前不同的条件判断,决定这个配置类是否生效!

  • 一但这个配置类生效;这个配置类就会给容器中添加各种组件;

  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

  • 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;

  • 配置文件能配置什么就可以参照某个功能对应的这个属性类

1 //从配置文件中获取指定的值和bean的属性进行绑定
2 //这个 ConfigurationProperties 中的 prefix 就可以在springBoot的yml 
3 //配置文件中使用层级的方式为其赋值
4 @ConfigurationProperties(prefix = "spring.http") 
5 public class HttpProperties {
6     // .....
7 }

 

我们去配置文件里面试试前缀,看提示!

 

 

 

联系起来 【自己总结精髓】

从spring.factories 配置文件中加载的mavenjar  对应这相应的配置类 

配置类上的注解  

@EnableConfigurationProperties(HttpEncodingProperties.class)  
这个注解里面的 xxx.properties.class 就对应这相应的实体类 这个配置类的相应值就可以从这个实体类中获取,
这个实体类中的属性值又可以通过springBoot ysm配置文件中进行赋值
【串起来】
然后这个配置类是从 spring.factories 点击进来的
这个文件就是SpringBoot自动装配所有的依赖
他是从主程序@springBootApplicaion注解中依次点击到 @Import({AutoConfigurationImportSelector.class}) 注解中获取的
这里面的方法就会去读取这个配置文件 spring.factories

自动配置总结:

1、SpringBoot启动会加载大量的自动配置类 【从主程序的入口的@springBootApplication 注解一次点击 获取到 spring.factories 中配置的maven jar ,点击进去对应着一个一个的配置类】

2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;【即我们是否在pom.xml中配置了相应的starer启动器,没有配置,点击去的maven jar 就会报红】

3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)

4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;

xxxxAutoConfigurartion:自动配置类;给容器中添加组件 【这个是在spring.factories配置文件中声明的】

xxxxProperties:封装配置文件中相关属性;【 这个是在从spring.factories配置文件中点击进去后的类上到的注解@EnableConfigurationProperties(HttpEncodingProperties.class),  XXX.class 就是对呀的配置类实体,这个类中的一些值可以从这里面获取,实体中的值又可以从yml配置文件中设置

 

 

了解:@Conditional

了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效;

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

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

 

即 @ConditionalOnxxx 注解的使用

 

 

那么多的自动配置类,必须在一定的条件下才能生效;也就是说,我们加载了这么多的配置类,但不是所有的都生效了。

我们怎么知道哪些自动配置类生效?

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

 1 #开启springboot的调试类 2 debug=true 

Positive matches:(自动配置类启用的:正匹配)

Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)

Unconditional classes: (没有条件的类)

 

 

 SpringBootWeb开发静态资源的处理 :[今天资源文件可以存放的位置,springBoot给我们提供了几个文件夹的位置]

使用SpringBoot的步骤:

1、创建一个SpringBoot应用,选择我们需要的模块,SpringBoot就会默认将我们的需要的模块自动配置好

2、手动在配置文件中配置部分配置项目就可以运行起来了

3、专注编写业务代码,不需要考虑以前那样一大堆的配置了。

要熟悉掌握开发,之前学习的自动配置的原理一定要搞明白!

比如SpringBoot到底帮我们配置了什么?我们能不能修改?我们能修改哪些配置?我们能不能扩展?

  • 向容器中自动配置组件 :*** Autoconfiguration

  • 自动配置类,封装配置文件的内容:***Properties

 

静态资源处理:

静态资源映射规则

首先,我们搭建一个普通的SpringBoot项目,回顾一下HelloWorld程序!

写请求非常简单,那我们要引入我们前端资源,我们项目中有许多的静态资源,比如css,js等文件,这个SpringBoot怎么处理呢?

如果我们是一个web应用,我们的main下会有一个webapp,我们以前都是将所有的页面导在这里面的,对吧!

但是我们现在的pom呢,打包方式是为jar的方式,那么这种方式SpringBoot能不能来给我们写页面呢?

当然是可以的,但是SpringBoot对于静态资源放置的位置,是有规定的!

 

方式一: webjars方式:

我们先来聊聊这个静态资源映射规则:

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

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

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

 1 @Override
 2 public void addResourceHandlers(ResourceHandlerRegistry registry) {
 3     if (!this.resourceProperties.isAddMappings()) {
 4         // 已禁用默认资源处理
 5         logger.debug("Default resource handling disabled");
 6         return;
 7     }
 8     // 缓存控制
 9     Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
10     CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
11     // webjars 配置
12     if (!registry.hasMappingForPattern("/webjars/**")) {
13         customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
14                                              .addResourceLocations("classpath:/META-INF/resources/webjars/")
15                                              .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
16     }
17     // 静态资源配置
18     String staticPathPattern = this.mvcProperties.getStaticPathPattern();
19     if (!registry.hasMappingForPattern(staticPathPattern)) {
20         customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
21                                              .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
22                                              .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
23     }
24 }

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

 

什么是webjars 呢? [即将我们以前导入的jquery.js 打成jar包 然后在项目中的pom.xml文件中以依赖的方式引入使用]

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

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

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

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

 1 <dependency> 2 <groupId>org.webjars</groupId> 3 <artifactId>jquery</artifactId> 4 <version>3.4.1</version> 5 </dependency> 

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

 

 

 

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

 

 

 

 

第二种静态资源映射规则

那我们项目中要是使用自己的静态资源该怎么导入呢?我们看下一行代码;

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

 1 // 进入方法
 2 public String[] getStaticLocations() {
 3     return this.staticLocations;
 4 }
 5 // 找到对应的值
 6 private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
 7 // 找到路径
 8 private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { 
 9     "classpath:/META-INF/resources/",
10   "classpath:/resources/", 
11     "classpath:/static/", 
12     "classpath:/public/" 
13 };

 

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

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

 1 "classpath:/META-INF/resources/" 2 "classpath:/resources/" 3 "classpath:/static/" 4 "classpath:/public/" 

 

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

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

 

自定义静态资源路径

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

 1 spring.resources.static-locations=classpath:/coding/,classpath:/kuang/ 

 

首页处理

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

 1 @Bean
 2 public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
 3                                                            FormattingConversionService mvcConversionService,
 4                                                            ResourceUrlProvider mvcResourceUrlProvider) {
 5     WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
 6         new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), // getWelcomePage 获得欢迎页
 7         this.mvcProperties.getStaticPathPattern());
 8     welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
 9     return welcomePageHandlerMapping;
10 }

点进去继续看

 1 private Optional<Resource> getWelcomePage() {
 2     String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
 3     // ::是java8 中新引入的运算符
 4     // Class::function的时候function是属于Class的,应该是静态方法。
 5     // this::function的funtion是属于这个对象的。
 6     // 简而言之,就是一种语法糖而已,是一种简写
 7     return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
 8 }
 9 // 欢迎页就是一个location下的的 index.html 而已
10 private Resource getIndexHtml(String location) {
11     return this.resourceLoader.getResource(location + "index.html");
12 }

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

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

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

 

网站图标

关于网站图标的问题,这个springBoot的版本会影响这个功能,高版本代码已经不存在了,不支持这个功能了

与其他静态资源一样,Spring Boot在配置的静态内容位置中查找 favicon.ico。如果存在这样的文件,它将自动用作应用程序的favicon。

1、关闭SpringBoot默认图标

 1 #关闭默认图标 2 spring.mvc.favicon.enabled=false 

2、自己放一个图标在静态资源目录下,我放在 public 目录下

3、清除浏览器缓存!刷新网页,发现图标已经变成自己的了!

 

 

总结:

因为springBoot执行的是一个web项目  

之前我们新建的都不是web项目,然后我们的静态资源都可以放在项目里面,然后在页面上引入

现在springBoot的web项目我们不能像之前一样使用静态资源

然后这个框架内部自动装配了静态资源配置类,他配置好了一些指定的文件夹供我们将静态资源放在其中然后在项目中使用

当然也可以使用 webjars的方式,将静态资源打成jar包然后在pom.xml中使用依赖的方式进行使用

然后我们的首页以及图标的制定 首页的位置这个框架也给我们配置好了,图标的话我们只需要在项目classpath:目录下放置  favicon.ico   就行 项目启动后会有自定义图标

但是这个受springBoot版本的影响。

 

 

 Thymeleaf模板引擎:

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

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

那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎么办呢?

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

模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图:

 

使用springBoot不支持前台获取值 不能直接使用html 所以为了能够使得我们能够使用 html 并且在前台取值 推出了模板引擎这个东西支持我们使用。

 

模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介绍一下SpringBoot给我们推荐的Thymeleaf模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他的这个语法更简单。而且呢,功能更强大。

我们呢,就来看一下这个模板引擎,那既然要看这个模板引擎。首先,我们来看SpringBoot里边怎么用。

 

 

引入Thymeleaf

怎么引入呢,对于springboot来说,什么事情不都是一个start的事情嘛,我们去在项目中引入一下。给大家三个网址:

Thymeleaf 官网:https://www.thymeleaf.org/

Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf

Spring官方文档:找到我们对应的版本

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

找到对应的pom依赖:可以适当点进源码看下本来的包!

 1 <!--thymeleaf--> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-thymeleaf</artifactId> 5 </dependency> 

 

Maven会自动下载jar包,我们可以去看下下载的东西;

 

 

 

前面呢,我们已经引入了Thymeleaf,那这个要怎么使用呢?

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

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

 1 @ConfigurationProperties(
 2     prefix = "spring.thymeleaf"
 3 )
 4 public class ThymeleafProperties {
 5     private static final Charset DEFAULT_ENCODING;
 6     public static final String DEFAULT_PREFIX = "classpath:/templates/";
 7     public static final String DEFAULT_SUFFIX = ".html";
 8     private boolean checkTemplate = true;
 9     private boolean checkTemplateLocation = true;
10     private String prefix = "classpath:/templates/";
11     private String suffix = ".html";
12     private String mode = "HTML";
13     private Charset encoding;
14 }

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

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

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

 

我们要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。

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

 1 xmlns:th="http://www.thymeleaf.org" 

测试页面取出数据:【类似于el表达式】

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>狂神说</title>
 6 </head>
 7 <body>
 8 <h1>测试页面</h1>
 9 
10 <div th:text="${msg}"></div>
11 <!--不转义-->
12 <div th:utext="${msg}"></div>
13 
14 <!--遍历数据-->
15 <!--th:each每次遍历都会生成当前这个标签:官网#9-->
16 <h4 th:each="user :${users}" th:text="${user}"></h4>
17 
18 <h4>
19     <!--行内写法:官网#12-->
20     <span th:each="user:${users}">[[${user}]]</span>
21 </h4>
22 
23 </body>
24 </html>

 

 

 springBoot MVC自动配置原理:

 

 

 

 1 springBoot自动配置 springmvc 给我们装配了什么,做了什么扩展,我们如何定制自己的一些关于mvc的功能?
 2 
 3     springBoot自动装配了viewResolve,即我们之前的视图器解析器 分析步骤:
 4     我们在WebMvcAutoConfiguration中去寻找springBoot 做了什么 
 5         WebMvcAutoConfiguration类中
 6             viewResolver()方法 这个方法使用 ConditionalOnMissingBean注解 配置了ContentNegotiatingViewResolver.class 7             ContentNegotiatingViewResolver 类继承了 WebApplicationObjectSupport
 8                 resolveViewName()方法 --> 对应的解析视图
 9                     调用getCandidateViews()方法 将所有的视图解析器拿来,进行while循环,挨个解析
10                         有个 viewResolvers 属性
11                             他是在 initServletContext()方法中赋值的  // 这里它是从beanFactory工具中获取容器中的所有视图解析器 
12                             // ViewRescolver.class 把所有的视图解析器来组合的
13                                 ContentNegotiatingViewResolver回去找所有的视图解析器,所以我们可以自己定义一个视图解析器,
14                                 给了相关的配置,springBoot会自动帮我们找到,我们就可以自定义一些自己的功能操作。
15 
16 
17 扩展使用SpringMVC:分析步骤:
18 WebMvcAutoConfiguration  类中
19     WebMvcAutoConfigurationAdapter 类 
20         @Import(EnableWebMvcConfiguration.class)
21             EnableWebMvcConfiguration 继承 DelegatingWebMvcConfiguration
22                 DelegatingWebMvcConfiguration 继承 WebMvcConfigurationSupport  // 从容器中获取所有的webmvcConfigurer
23                     addViewControllers()方法 调用 addViewControllers()  // 将所有的WebMvcConfigurer相关配置来一起调用!包括我们自己配置的和Spring给我们配置的
24                     
25                     
26                     
27 全面接管SpringMVC:这样原本的springBoot自动给我们配置的功能就会失效,只会使用我们自己定义好的功能,不推荐使用。
28 使用 @EnableWebMvc 注解 
29     导入了 @Import(DelegatingWebMvcConfiguration.class) DelegatingWebMvcConfiguration.class
30         DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport类 
31             WebMvcConfigurationSupport类在 WebMvcAutoConfiguration 自动装配类中有一个注解 
32                 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) //意思是不存在这个 WebMvcConfigurationSupport 类的时候springBoot的自动配置MVC生效
33                     这个注解导入了 WebMvcConfigurationSupport  
34                         @EnableWebMvc 注解中的类 中也继承了 WebMvcConfigurationSupport  
35                             所以如果使用了 @EnableWebMvc 那么就相当于手动配置了 WebMvcConfigurationSupport 类 ,那么在 WebMvcConfigurationSupport 这个自动配置类
36                             中的 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 就会生效,生效后这个自动配置类就无效了,只会使用我们手动配置的功能。
37                             (不推荐)

 

 

 MVC自动配置原理:

在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制。

只有把这些都搞清楚了,我们在之后使用才会更加得心应手。途径一:源码分析,途径二:官方文档!

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

 1 Spring MVC Auto-configuration
 2 // Spring Boot为Spring MVC提供了自动配置,它可以很好地与大多数应用程序一起工作。
 3 Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
 4 // 自动配置在Spring默认设置的基础上添加了以下功能:
 5 The auto-configuration adds the following features on top of Spring’s defaults:
 6 // 包含视图解析器
 7 Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
 8 // 支持静态资源文件夹的路径,以及webjars
 9 Support for serving static resources, including support for WebJars 
10 // 自动注册了Converter:
11 // 转换器,这就是我们网页提交数据到后台自动封装成为对象的东西,比如把"1"字符串自动转换为int类型
12 // Formatter:【格式化器,比如页面给我们了一个2019-8-10,它会给我们自动格式化为Date对象】
13 Automatic registration of Converter, GenericConverter, and Formatter beans.
14 // HttpMessageConverters
15 // SpringMVC用来转换Http请求和响应的的,比如我们要把一个User对象转换为JSON字符串,可以去看官网文档解释;
16 Support for HttpMessageConverters (covered later in this document).
17 // 定义错误代码生成规则的
18 Automatic registration of MessageCodesResolver (covered later in this document).
19 // 首页定制
20 Static index.html support.
21 // 图标定制
22 Custom Favicon support (covered later in this document).
23 // 初始化数据绑定器:帮我们把请求数据绑定到JavaBean中!
24 Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
25 
26 /*
27 如果您希望保留Spring Boot MVC功能,并且希望添加其他MVC配置(拦截器、格式化程序、视图控制器和其他功能),则可以添加自己
28 的@configuration类,类型为webmvcconfiguer,但不添加@EnableWebMvc。如果希望提供
29 RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义
30 实例,则可以声明WebMVCregistrationAdapter实例来提供此类组件。
31 */
32 If you want to keep Spring Boot MVC features and you want to add additional MVC configuration 
33 (interceptors, formatters, view controllers, and other features), you can add your own 
34 @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide 
35 custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or 
36 ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
37 
38 // 如果您想完全控制Spring MVC,可以添加自己的@Configuration,并用@EnableWebMvc进行注释。
39 If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

 

我们来仔细对照,看一下它怎么实现的,它告诉我们SpringBoot已经帮我们自动配置好了SpringMVC,然后自动配置了哪些东西呢?

ContentNegotiatingViewResolver 内容协商视图解析器

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

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

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

 1 @Bean
 2 @ConditionalOnBean(ViewResolver.class)
 3 @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
 4 public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
 5     ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
 6     resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
 7     // ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,因此它应该具有较高的优先级
 8     resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
 9     return resolver;
10 }

我们可以点进这类看看!找到对应的解析视图的代码;

 

 1 @Nullable // 注解说明:@Nullable 即参数可为null
 2 public View resolveViewName(String viewName, Locale locale) throws Exception {
 3     RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
 4     Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
 5     List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
 6     if (requestedMediaTypes != null) {
 7         // 获取候选的视图对象
 8         List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
 9         // 选择一个最适合的视图对象,然后把这个对象返回
10         View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
11         if (bestView != null) {
12             return bestView;
13         }
14     }
15     // .....
16 }

我们继续点进去看,他是怎么获得候选的视图的呢?

getCandidateViews中看到他是把所有的视图解析器拿来,进行while循环,挨个解析!

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

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

 1 protected void initServletContext(ServletContext servletContext) {
 2     // 这里它是从beanFactory工具中获取容器中的所有视图解析器
 3     // ViewRescolver.class 把所有的视图解析器来组合的
 4     Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
 5     ViewResolver viewResolver;
 6     if (this.viewResolvers == null) {
 7         this.viewResolvers = new ArrayList(matchingBeans.size());
 8     }
 9     // ...............
10 }

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

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

1、我们在我们的主程序中去写一个视图解析器来试试;

 1 @Bean //放到bean中
 2 public ViewResolver myViewResolver(){
 3     return new MyViewResolver();
 4 }
 5 
 6 //我们写一个静态内部类,视图解析器就需要实现ViewResolver接口
 7 private static class MyViewResolver implements ViewResolver{
 8     @Override
 9     public View resolveViewName(String s, Locale locale) throws Exception {
10         return null;
11     }
12 }

2、怎么看我们自己写的视图解析器有没有起作用呢?

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

 

 

3、我们启动我们的项目,然后随便访问一个页面,看一下Debug信息; 找到this

 

 找到视图解析器,我们看到我们自己定义的就在这里了;

 

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

 

转换器和格式化器

找到格式化转换器:

@Bean
@Override
public FormattingConversionService mvcConversionService() {
    // 拿到配置文件中的格式化规则
    WebConversionService conversionService = 
        new WebConversionService(this.mvcProperties.getDateFormat());
    addFormatters(conversionService);
    return conversionService;
}

点击去:

1 public String getDateFormat() {
2     return this.dateFormat;
3 }
4 
5 /**
6 * Date format to use. For instance, `dd/MM/yyyy`. 默认的
7  */
8 private String dateFormat;

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

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

 

 

修改SpringBoot的默认配置

这么多的自动配置,原理都是一样的,通过这个WebMVC的自动配置原理分析,我们要学会一种学习方式,通过源码探究,得出结论;这个结论一定是属于自己的,而且一通百通。

SpringBoot的底层,大量用到了这些设计细节思想,所以,没事需要多阅读源码!得出结论;

SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(如果用户自己配置@bean),如果有就用用户配置的,如果没有就用自动配置的;

如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来!

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

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

我们要做的就是编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,还不能标注@EnableWebMvc注解;我们去自己写一个;我们新建一个包叫config,写一个类MyMvcConfig;

 1 //应为类型要求为WebMvcConfigurer,所以我们实现其接口
 2 //可以使用自定义类扩展MVC的功能
 3 @Configuration
 4 public class MyMvcConfig implements WebMvcConfigurer {
 5 
 6     @Override
 7     public void addViewControllers(ViewControllerRegistry registry) {
 8         // 浏览器发送/test , 就会跳转到test页面;
 9         registry.addViewController("/test").setViewName("test");
10     }
11 }

 

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

我们可以去分析一下原理:

1、WebMvcAutoConfiguration 是 SpringMVC的自动配置类,里面有一个类WebMvcAutoConfigurationAdapter

2、这个类上有一个注解,在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class)

3、我们点进EnableWebMvcConfiguration这个类看一下,它继承了一个父类:DelegatingWebMvcConfiguration

这个父类中有这样一段代码:

 1 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
 2     private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
 3     
 4   // 从容器中获取所有的webmvcConfigurer
 5     @Autowired(required = false)
 6     public void setConfigurers(List<WebMvcConfigurer> configurers) {
 7         if (!CollectionUtils.isEmpty(configurers)) {
 8             this.configurers.addWebMvcConfigurers(configurers);
 9         }
10     }
11 }

4、我们可以在这个类中去寻找一个我们刚才设置的viewController当做参考,发现它调用了一个

 1 protected void addViewControllers(ViewControllerRegistry registry) { 2 this.configurers.addViewControllers(registry); 3 } 

5、我们点进去看一下

 1 public void addViewControllers(ViewControllerRegistry registry) {
 2     Iterator var2 = this.delegates.iterator();
 3 
 4     while(var2.hasNext()) {
 5         // 将所有的WebMvcConfigurer相关配置来一起调用!包括我们自己配置的和Spring给我们配置的
 6         WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
 7         delegate.addViewControllers(registry);
 8     }
 9 
10 }

所以得出结论:所有的WebMvcConfiguration都会被作用,不止Spring自己的配置类,我们自己的配置类当然也会被调用;

 

全面接管SpringMVC

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

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

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

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

 

 

 

给配置类加上注解:@EnableWebMvc

 

 

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

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

思考问题?为什么加了一个注解,自动配置就失效了!我们看下源码:

1、这里发现它是导入了一个类,我们可以继续进去看

 1 @Import({DelegatingWebMvcConfiguration.class}) 2 public @interface EnableWebMvc { 3 } 

2、它继承了一个父类 WebMvcConfigurationSupport

1 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
2   // ......
3 }

3、我们来回顾一下Webmvc自动配置类

 1 @Configuration(proxyBeanMethods = false)
 2 @ConditionalOnWebApplication(type = Type.SERVLET)
 3 @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
 4 // 这个注解的意思就是:容器中没有这个组件的时候,这个自动配置类才生效
 5 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
 6 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
 7 @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
 8     ValidationAutoConfiguration.class })
 9 public class WebMvcAutoConfiguration {
10     
11 }

总结一句话:@EnableWebMvc将WebMvcConfigurationSupport组件导入进来了;

而导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能!

 

 

 

集成Swagger

swagger 项目中集成Swagger自动生成API文档 是一个实时更新的一个api文档 他也可以进行接口的测试(类似于postman)  可以查看接口的详细信息

出现前景 前后端分离  前后端人员可以实时的知道需要修改的东西 以前是直接编写word文档

但是会有信息的时间差。所以 swagger出现了。

 

SpringBoot集成Swagger

两个jar包:

  • Springfox-swagger2

  • swagger-springmvc

maven依赖:

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>

  

一、要使用Swagger,我们需要编写一个配置类-SwaggerConfig来配置 Swagger

1 @Configuration //配置类
2 @EnableSwagger2// 开启Swagger2的自动配置
3 public class SwaggerConfig {  
4 }

 

Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger。

在这个类中使用 Docket实例

1 @Bean //配置docket以配置Swagger具体参数
2 public Docket docket() {
3    return new Docket(DocumentationType.SWAGGER_2);
4 }

可以通过apiInfo()属性配置文档信息

 1 //配置文档信息
 2 private ApiInfo apiInfo() {
 3    Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
 4    return new ApiInfo(
 5            "Swagger学习", // 标题
 6            "学习演示如何配置Swagger", // 描述
 7            "v1.0", // 版本
 8            "http://terms.service.url/组织链接", // 组织链接
 9            contact, // 联系人信息
10            "Apach 2.0 许可", // 许可
11            "许可链接", // 许可连接
12            new ArrayList<>()// 扩展
13   );
14 }

Docket 实例关联上 apiInfo()

@Bean
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}

想使用的功能就在后面一直.调用方法就行

 1 @Bean
 2 public Docket docket(Environment environment) {
 3    // 设置要显示swagger的环境
 4    Profiles of = Profiles.of("dev", "test");
 5    // 判断当前是否处于该环境
 6    // 通过 enable() 接收此参数判断是否要显示
 7    boolean b = environment.acceptsProfiles(of);
 8    
 9    return new Docket(DocumentationType.SWAGGER_2)
10       .apiInfo(apiInfo())
11       .enable(b) //配置是否启用Swagger,如果是false,在浏览器将无法访问
12       .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
13       .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
14        // 配置如何通过path过滤,即这里只扫描请求以/kuang开头的接口
15       .paths(PathSelectors.ant("/kuang/**"))
16       .build();
17 }

 

配置分组:配置多个 Docket

 1 @Bean
 2 public Docket docket1(){
 3    return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
 4 }
 5 @Bean
 6 public Docket docket2(){
 7    return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
 8 }
 9 @Bean
10 public Docket docket3(){
11    return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
12 }

然后就是注解的使用;

在Controller层中 的类上 方法上 都可以使用  然后就会在swagger的访问页面出现相应的效果。

@ApiOperation("狂神的接口")
@PostMapping("/kuang")
@ResponseBody
public String kuang(@ApiParam("这个名字会被返回")String username){
   return username;
}

 

SpringBoot15:异步、定时、邮件任务:

异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,

直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。

编写方法,假装正在处理数据,使用线程设置一些延时,模拟同步等待的情况;

 1 @Service
 2 public class AsyncService {
 3 
 4    public void hello(){
 5        try {
 6            Thread.sleep(3000);
 7       } catch (InterruptedException e) {
 8            e.printStackTrace();
 9       }
10        System.out.println("业务进行中....");
11   }
12 }

 

异步的处理使用两个注解就可以了  

@Async
@EnableAsync //开启异步注解功能

一个是在具体的方法上一个是在主程序的类上 

问题:我们如果想让用户直接得到消息,就在后台使用多线程的方式进行处理即可,但是每次都需要自己手动去编写多线程的实现的话,

太麻烦了,我们只需要用一个简单的办法,在我们的方法上加一个简单的注解即可,如下:

给hello方法添加@Async注解;

 1 //告诉Spring这是一个异步方法
 2 @Async
 3 public void hello(){
 4    try {
 5        Thread.sleep(3000);
 6   } catch (InterruptedException e) {
 7        e.printStackTrace();
 8   }
 9    System.out.println("业务进行中....");
10 }

SpringBoot就会自己开一个线程池,进行调用!但是要让这个注解生效,我们还需要在主程序上添加一个注解@EnableAsync ,开启异步注解功能;

1 @EnableAsync //开启异步注解功能
2 @SpringBootApplication
3 public class SpringbootTaskApplication {
4 
5    public static void main(String[] args) {
6        SpringApplication.run(SpringbootTaskApplication.class, args);
7   }
8 
9 }

 

定时任务

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。

  • TaskExecutor接口

  • TaskScheduler接口

两个注解:

  • @EnableScheduling

  • @Scheduled

cron表达式:

 1 (1)0/2 * * * * ?   表示每2秒 执行任务
 2 (1)0 0/2 * * * ?   表示每2分钟 执行任务
 3 (1)0 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
 4 (2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
 5 (3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
 6 (4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点
 7 (5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
 8 (6)0 0 12 ? * WED   表示每个星期三中午12点
 9 (7)0 0 12 * * ?   每天中午12点触发
10 (8)0 15 10 ? * *   每天上午10:15触发
11 (9)0 15 10 * * ?     每天上午10:15触发
12 (10)0 15 10 * * ?   每天上午10:15触发
13 (11)0 15 10 * * ? 2005   2005年的每天上午10:15触发
14 (12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
15 (13)0 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
16 (14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
17 (15)0 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
18 (16)0 10,44 14 ? 3 WED   每年三月的星期三的下午2:10和2:44触发
19 (17)0 15 10 ? * MON-FRI   周一至周五的上午10:15触发
20 (18)0 15 10 15 * ?   每月15日上午10:15触发
21 (19)0 15 10 L * ?   每月最后一日的上午10:15触发
22 (20)0 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
23 (21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
24 (22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发

 

1、创建一个ScheduledService

我们里面存在一个hello方法,他需要定时执行,怎么处理呢?

 1 @Service
 2 public class ScheduledService {
 3    
 4    //秒   分   时     日   月   周几
 5    //0 * * * * MON-FRI
 6    //注意cron表达式的用法;
 7    @Scheduled(cron = "0 * * * * 0-7")
 8    public void hello(){
 9        System.out.println("hello.....");
10   }
11 }

这里写完定时任务之后,我们需要在主程序上增加@EnableScheduling 开启定时任务功能

 1 @EnableAsync //开启异步注解功能
 2 @EnableScheduling //开启基于注解的定时任务
 3 @SpringBootApplication
 4 public class SpringbootTaskApplication {
 5 
 6    public static void main(String[] args) {
 7        SpringApplication.run(SpringbootTaskApplication.class, args);
 8   }
 9 
10 }

 

邮件任务

邮件发送,在我们的日常开发中,也非常的多,Springboot也帮我们做了支持

  • 邮件发送需要引入spring-boot-start-mail

  • SpringBoot 自动配置MailSenderAutoConfiguration

  • 定义MailProperties内容,配置在application.yml中

  • 自动装配JavaMailSender

  • 测试邮件发送

 

引入pom依赖

 1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-mail</artifactId> 4 </dependency> 

 1 <dependency> 2 <groupId>com.sun.mail</groupId> 3 <artifactId>jakarta.mail</artifactId> 4 <version>1.6.4</version> 5 <scope>compile</scope> 6 </dependency> 

查看自动配置类:MailSenderAutoConfiguration

 

 

这个类中存在bean,JavaMailSenderImpl

 

 

然后我们去看下配置文件

 1 @ConfigurationProperties(
 2    prefix = "spring.mail"
 3 )
 4 public class MailProperties {
 5    private static final Charset DEFAULT_CHARSET;
 6    private String host;
 7    private Integer port;
 8    private String username;
 9    private String password;
10    private String protocol = "smtp";
11    private Charset defaultEncoding;
12    private Map<String, String> properties;
13    private String jndiName;
14 }

配置文件:

1 spring.mail.username=24736743@qq.com
2 spring.mail.password=你的qq授权码
3 spring.mail.host=smtp.qq.com
4 # qq需要配置ssl
5 spring.mail.properties.mail.smtp.ssl.enable=true

获取授权码:在QQ邮箱中的设置->账户->开启pop3和smtp服务

Spring单元测试

 1 @Autowired
 2 JavaMailSenderImpl mailSender;
 3 
 4 @Test
 5 public void contextLoads() {
 6    //邮件设置1:一个简单的邮件
 7    SimpleMailMessage message = new SimpleMailMessage();
 8    message.setSubject("通知-明天来狂神这听课");
 9    message.setText("今晚7:30开会");
10 
11    message.setTo("24736743@qq.com");
12    message.setFrom("24736743@qq.com");
13    mailSender.send(message);
14 }
15 
16 @Test
17 public void contextLoads2() throws MessagingException {
18    //邮件设置2:一个复杂的邮件
19    MimeMessage mimeMessage = mailSender.createMimeMessage();
20    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
21 
22    helper.setSubject("通知-明天来狂神这听课");
23    helper.setText("<b style='color:red'>今天 7:30来开会</b>",true);
24 
25    //发送附件
26    helper.addAttachment("1.jpg",new File(""));
27    helper.addAttachment("2.jpg",new File(""));
28 
29    helper.setTo("24736743@qq.com");
30    helper.setFrom("24736743@qq.com");
31 
32    mailSender.send(mimeMessage);
33 }

 

 

分布式理论:

之前我们写的业务项目是在一台电脑上 在该电脑上一个方法调用本电脑上的一个方法
分布式 将一个庞大的系统的相关业务 拆分开 放在不同的服务器上即不同的电脑上
在一台电脑上的一个方法中调用另外一台电脑上的一个方法
此时面临一个问题 两台电脑分别部署在不同的地方 即在不同的网络中
此时就出现了一个新的网络传输 RCP 他和http是一样的 及网络协议
RCP即远程调用另外网络中的资源
所以此时出现了 Dubbo
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:
面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现
服务自动注册:这里的服务自动注册中心就有很多种类 其中zookeeper 就是其中的一个
所以: 分布式 -->RCP --> Dubbo --> zookepper
这里面会涉及到一些其他技术 负载均衡 springCloud Redis
swagger就是一个实时可更新的项目接口的api 也有和postman类似的测试功能

 

然后就是 Dubbo zookeeper 在springBoot项目中的集成。安装。

 

 

springmvc -->  spring  -->  springBoot --> 分布式 --> springCloud  --> 负载均衡  --> RCP -->  Dubbo  --> zookepper  -->  服务网格 。。。。

 

三层架构  + MVC 

  架构  ----->解耦

开发框架 

  Spring 

    IOC    AOP 

      IOC  :  控制反转  之前我们创建Bean 的方式是自己手动创建 new 现在交由 spring容器进行管理 使得它给我们创建 Bean 对象

         即: 原来我们都是自己一步步操作,现在交给容器了,我们需要什么就去拿就可以了

      AOP : 切面 (本质:动态代理)

         在不影响业务本来的情况下,实现动态增加功能,大量应用在日志,事务...等等方面 

  Spring是一个轻量级的java开源框架,容器

  目的:解决企业开发的复杂性问题

  Spring十分复杂,配置文件。

 

  SpringBoot 

    SpringBoot并不是一个新的东西,就是Spring的升级版!

    新一代JavaEE的开发标准,开箱即用! --> 拿过来就可以用!

    它自动帮我们配置了非常多的东西,我们拿来即用! 所以最核心的东西 自动装配

    特性:约定大于配置!

随着项目越来越大,用户越来越多 我们原本的单体项目就不能够支撑了,所以~

 

 微服务架构  -->新架构

   模块化, 功能化!

   如:用户模块,支付模块,签到模块,娱乐模块等....

   方式一:

      模块越来越多,然后一台服务器解决不了所以增加服务器,横向

   假设A服务器占用了98%资源,B服务器只占用了10%   可以使用负载均衡方式来解决

   方式二:

   将原来的整体项目,分模块化,用户就是一个单独的项目,签到也是一个单独的项目,分布式的形成

   项目和项目之间需要通信,如何通信?

   用户非常多,而签到十分少!给用户多一点服务器,给签到少一点服务器!

 

微服务架构问题?

   分布式架构会遇到的四个核心问题?

   1、这么多服务,客户端该如何去访问?

   2、这么多服务,服务之间如何进行通信?

   3、这么多服务,如何治理呢?

   4、服务挂了,怎么办?

 

解决方案:

    SpringCloud,是一套生态,就是用来解决以上分布式架构的四个问题

    想要使用SpringCloud 必须掌握 SpringBoot 因为SpringCloud是基于SpringBoot.

    

    1、Spring Cloud NetFlix 提出一套解决方案 一站式解决方案

      Api 网关, zuul组件

      Feign -->HttpClient -->Http的通信方式 同步并阻塞 (底层是http)

      服务注册与发现 ,Eureka

      熔断机制 Hystrix

 

    2、Apache Dubbo Zookeeper 第二套解决方案

      API : 没有! 要么找第三方组件,要么自己实现

      Dubbo是一个高性能的基于Java实现的 RCP通信框架 

      服务注册与发现,zookeeper 动物园管理者 (Hadoop,Hive)

      熔断机制没有 借助了Hystrix

 

    3、alibaba

 

    4、服务网格

      下一代服务标准 Server Mesh

      代表解决方案: istio 

 

    1.API网关,服务路由

    2.HTTP,RPC框架

    3.服务注册与发现,高可用

    4.熔断机制,服务降级

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2021-10-28 09:26  易言。  阅读(803)  评论(0)    收藏  举报