SpringBoot详解-程序员宅基地

技术标签: spring boot  java  

前言

所有的技术框架的发展似乎都遵循了一条主线规律:

  1. 从一个复杂应用场景衍生一种规范框架, 人们只需要进行各种配置而不需要自己去实现它, 这时候强大的配置功能成了优点;
  2. 发展到一定程度之后, 人们根据实际生产应用情况, 选取其中实用功能和设计精华, 重构出一些轻量级的框架;
  3. 之后为了提高开发效率, 嫌弃原先的各类配置过于麻烦, 于是开始提倡 “约定大于配置″, 进而衍生出一些一站式的解决方案。
    这就是 Java 企业级应用 ->J2EE-> spring-> spring boot 的过程。

一、SpringBoot 是什么?

1.1、概念

  • SpringBoot 是一个 javaweb 开发的框架。
  • 对比于其他 Javaweb 框架,更简化开发,约定大于配置。

1.2、目的

  • 让大家更容易使用 spring,更容易集成各种常用的中间件、开源软件。
  • SpringBoot 基于 Spring 开发, SpringBoot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。
  • SpringBoot 不是用来替代 spring 的解决方案,而是和 spring 框架紧密结合提升 spring 开发者体验的工具。

1.3、什么是微服务

  • 微服务是一种架构风格, 它要求我们在开发一个应用的时候, 这个应用必须构建成一系列小服务的组合; 可以通过 http 的方式进行互通。
  • MVC 架构,MVVM 架构,微服务架构。
  • 微服务架构, 就是把每个功能元素独立出来。把独立出来的功能元素的动态组合, 需要的功能元素才去拿来组合, 需要多一些时可以整合多个功能元素。
  • 所以微服务架构是对功能元素进行复制, 而没有对整个应用进行复制。

优点:1. 节省了调用资源。2. 每个功能元素的服务都是一个可替换的、可独立升级的软件代码。

1.4、单体应用架构

  • 单体应用架构 (all in one) 是指,我们将一个应用的中的所有应用服务都封装在一个应用中;
  • 无论是 ERP、CRM 或是其他什么系统看,都把数据库访问,web 访问,等等各个功能放到一个 war 包内。

优点:易于开发和测试,方便部署;当需要扩展时,只需要将 war 复制多份, 然后放到多个服务器上, 再做个负载均衡就可以了。
缺点:修改一个非常小的地方, 都需要停掉整个服务, 重新打包部署这个应用 War 包;对于一个大型应用,如何维护,如何分工合作都是问题。

1.5、如何构建微服务

二、SpringBoot 原理

2.1、pom.xml

  1. spring-boot-dependencie:核心依赖在父工程中。大部分依赖的版本都是在父工程中管理着,我们拿过来调用即可,因此我们引用一些依赖时不需要指定版本。并且父工程中已经帮我们配置好资源过滤和一些插件。

2.2、启动器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  1. 启动器其实就是 springboot 的启动场景,比如 spring-boot-starter-web 启动器会帮我们自动导入 web 环境所有依赖。
  2. springboot 会将所有的功能场景,都变成一个个启动器。
  3. 我们要使用什么功能,只需要找到对应的启动器就可以了即 starter

2.3、主程序

2.3.1、注解

@SpringBootApplication

  1. @SpringBootConfiguration:springboot 的配置。
  2. @EnableAutoConfiguration:自动导入配置。
    1. @AutoConfigurationPackage:自动配置包。
      • @Import({Registrar.class}):自动配置包注册。
    2. @Import({AutoConfigurationImportSelector.class}):自动配置导入选择器。(自动导包的核心)
  3. @ComponentScan():扫描当前主启动类同级的包。(扫描的包到 Registrar.class 注册)

自动导包的核心 AutoConfigurationImportSelector 类:选择了什么东西
AutoConfigurationImportSelector 类中的方法:

// 1.获得自动配置实体(调用“获取所有候选配置”的方法获取实体)。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)
// 2.获取所有候选配置(候选配置是哪些配置)。
List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes){
   
    
    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;
}
// 3.候选配置是所有标注@EnableAutoConfiguration注解的类下的所有配置。(即获取主启动类下的所有配置)
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
   
    
        return EnableAutoConfiguration.class;
    }
// 4.获取所有的配置从哪里来,上面第二个方法调用了loadFactoryNames方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
   
    
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
// 5.loadFactoryNames方法调用了loadSpringFactories方法
// 6.loadSpringFactories方法从项目资源和系统资源中获取配置文件
classLoader.getResources("META-INF/spring.factories") ClassLoader.getSystemResources("META-INF/spring.factories")

META-INF/spring.factories:自动配置的核心文件。

// 遍历所有的资源,封装成properties供我们使用
Properties properties = PropertiesLoaderUtils.loadProperties(resource);

结论: springboot 所有自动配置都是在启动的时候扫描并加载: 所有的自动配置类都在 spring.factories 里面,但是不一定生效;要判断条件是否成立:只要导入了对应的 start,就有对应的启动器,有了启动器,我们自动装配就会生效,然后自动配置就可以成功。

详细步骤

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

2.3.2、Run 方法

main 方法中的 run 方法启动会开启一个服务。

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

2.3.3、SpringApplication.run 分析

主要两部分

  • 一是 SpringApplication 的实例化。
  • 二是 run 方法的执行。

2.3.4、SpringApplication 类主要做了四件事情

  • 判断应用的类型是普通项目还是 web 项目。(普通项目直接就结束了,web 项目可以一直启动)
  • 查找并加载所有可用初始化器,设置到 initializers 属性中。
  • 查找所有的应用程序监听器,设置到 listeners 属性中。(获取上下文处理 bean)
  • 推断并设置 main 方法的定义类,找到运行的主类。

2.4、自动装配再理解

springboot 配置文件能够配置的东西都有一个固有的规律:
他们都有对应的 xxxAutoConfiguration 配置类,这个配置类都会绑定一个 xxxProperties 类,xxxProperties 类和 springboot 的配置文件绑定;这样我们就可以在 springboot 配置文件中自定义配置了。

2.4.1、自动装配原理再理解

  1. springboot 启动会加载大量的自动配置类。
  2. 我们要看我们需要的功能有没有在 springboot 默认写好的自动配置类中。
  3. 我们看这个自动配置类中配置了哪些组件。(不存在就需要全部手动写,如果存在我们就不需要再手动配置;也可以自定义配置覆盖默认的配置)
  4. 给容器中自动配置类添加组件时,会从 xxxProperties 类中获取相应的属性。我们只需要在 springboot 配置中指定这些属性就可以了。
  • xxxAutoConfiguration:自动配置类(给容器中添加组件)
  • xxxProperties:封装配置文件中的属性

2.5、自动配置类中存放了大量的配置没有全部都生效的原因

spring 的底层注解:根据不同的条件,来判断当前配置或者类是否生效。@Conditionalxxx

三、SpringBoot

3.1、yaml 语法

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

  • application.properties(语法结构:key=value)
  • application.yml(语法结构:key: 空格 value)

全局配置文件的作用:修改 SpringBoot 自动配置的默认值,它会在底层帮我们自动配置。

3.1.1、基本语法

# 对象
student:
  name: 'zs'
  age: 12
# 对象的行内写法
student1: {
   
    name: 'zs',age: 12}
# 数组
pets:
  - cat
  - dog
  - pig
# 数组行内写法
pets1: [cat,dog,pig]

3.1.2、@ConfigurationProperties绑定 application.yml 配置的属性(属性需要 set 方法才能取值)

/*
ConfigurationProperties作用
将yml配置文件中配置的每个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和yml配置文件中相关的配置进行绑定;
参数prefix="person":将yml配置文件中的person下面的所有属性和本类属性对应。
(只有这个组件是容器中的组件,才能使用容器提供的ConfigurationProperties功能)
 */
 // 可以直接拿到复杂类型的值
@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
   
    
    private String name;
    private Integer age;
    private Boolean flag;
    private Date birth;
    private Map<String,Object> map;
    private List<Object> list;
    private Dog dog;
}
// application.yml
person:
  name: zs
  age: 12
  flag: false
  birth: 2021/04/20
  map: {
   
    k1: v1,k2: v2}
  list: [code,music,girl]
  dog:
    name: 旺财
    age: 3
<!--spring-boot-configuration-processor依赖可以在yml配置时给出提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

3.1.3、@Configuration@Value配合取值(没有 set 方法也可以取值)

// 复杂类型不能用@Value直接取值
@Configuration
@Data
public class Person {
   
    
    @Value("${person222.name}")
    private String name;
    @Value("${person222.age}")
    private Integer age;
    @Value("${person222.flag}")
    private Boolean flag;
    @Value("${person222.birth}")
    private Date birth;
    private Map<String,Object> map;
    private List<Object> list;
    private Dog dog;
}
// application.yml
person222:
  name: zs
  age: 12
  flag: false
  birth: 2021/04/20
  map: {
   
    k1: v1,k2: v2}
  list: [code,music,girl]
  dog:
    name: 旺财
    age: 3

3.1.4、@PropertySource读取 xxx.properties 配置(没有 set 方法也可以取值)

@Component
@PropertySource(value = "classpath:test.properties")//可以这样配置@PropertySource({"classpath:test.properties"})
@Data
public class Person {
   
    
    // SPEL表达式取出配置文件的值
    @Value("${name}")
    private String name;
    @Value("${age}")
    private Integer age;
    private Boolean flag;
    private Date birth;
    private Map<String,Object> map;
    private List<Object> list;
    private Dog dog;
}
// test.properties
name=zhangsan
age=13

3.1.5、松散绑定

yml 配置属性的 - 可以和实体属性的驼峰对应绑定

@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
   
    
    private String firstName;
}
// application.yml
person:
  first-name: zs

3.1.6、JSR303 数据校验

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

HibernateValidator 是 BeanValidation 的参考实现;HibernateValidator 提供了 JSR 303 规范中所有内置 constraint 的实现;和附加的 constraint

HibernateValidator 附加的 constraint

3.2、多环境配置和配置文件位置

3.2.1、配置文件位置

3.2.2、多环境配置切换

四、SpringBootWeb 开发

4.1、SpringBootWeb 开发需要解决的问题

  • 导入静态资源
  • 首页定制
  • 模板引擎 Thymeleaf
  • 装配扩展 springMVC
  • 增删改查
  • 拦截器
  • 国际化
  • SpringMvcConfig 配置
  • 错误页定制

4.2、静态资源导入

  1. 在 SpringBoot,可以使用以下方式处理静态资源。
    • webjars 文件夹下:映射访问 localhost:8080/webjars/
    • public 文件夹,static 文件夹,resources 文件夹下和 /**(即 classpath:):映射访问 localhost:8080/
  2. 文件夹优先级(即访问一个静态文件先查找 resources 文件夹):resources>static>public

4.3、首页定制和图标定制

4.3.1、首页定制

  1. 首页名称需要是 index.html
  2. index.html 放在静态资源文件夹下(resources,static,public)
  3. localhost:8080 / 就可以访问到 index.html 页面

4.3.2、老版本 springboot 支持 (2.1.7)

  1. favicom.ico 图标放在 static 文件夹下。
  2. 配置关闭默认的图标 spring.mvc.favicon.ico.enabled=false

4.4、模板引擎 Thymeleaf

4.4.1、thymeleaf 使用步骤

  1. 导入 jar 包
<!--thymeleaf,我们都是基于3.x开发;2.x项目会报错-->
<dependency>
 <groupId>org.thymeleaf</groupId>
 <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
 <groupId>org.thymeleaf.extras</groupId>
 <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
  1. ThymeleafProperties 默认配置
  2. controller 跳转
  3. xxx.html 放在 templates 文件夹下

    xxx.html 页面上使用 thymeleaf 语法,需要引入头文件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
 <meta charset="UTF-8">
 <title>首页</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>

4.4.2、thymeleaf 语法

  1. html和css的元素都可以被thymeleaf接管。
  2. ${}用来取值,
  3. @{}用来表示url。
  4. 消息文字的表达式#{} 。
  5. 提取公共页面。
    • th:fragment=”siderbar”

4.5、扩展 springMVC

package com.sywl.config;
import org.springframework.context.annotation.Configuration;
import org.springframework
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34124252/article/details/126246129

智能推荐

JWT(Json Web Token)实现无状态登录_无状态token登录-程序员宅基地

文章浏览阅读685次。1.1.什么是有状态?有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?服务端保存大量数据,增加服务端压力 服务端保存用户状态,无法进行水平扩展 客户端请求依赖服务.._无状态token登录

SDUT OJ逆置正整数-程序员宅基地

文章浏览阅读293次。SDUT OnlineJudge#include<iostream>using namespace std;int main(){int a,b,c,d;cin>>a;b=a%10;c=a/10%10;d=a/100%10;int key[3];key[0]=b;key[1]=c;key[2]=d;for(int i = 0;i<3;i++){ if(key[i]!=0) { cout<<key[i.

年终奖盲区_年终奖盲区表-程序员宅基地

文章浏览阅读2.2k次。年终奖采用的平均每月的收入来评定缴税级数的,速算扣除数也按照月份计算出来,但是最终减去的也是一个月的速算扣除数。为什么这么做呢,这样的收的税更多啊,年终也是一个月的收入,凭什么减去12*速算扣除数了?这个霸道(不要脸)的说法,我们只能合理避免的这些跨级的区域了,那具体是那些区域呢?可以参考下面的表格:年终奖一列标红的一对便是盲区的上下线,发放年终奖的数额一定一定要避免这个区域,不然公司多花了钱..._年终奖盲区表

matlab 提取struct结构体中某个字段所有变量的值_matlab读取struct类型数据中的值-程序员宅基地

文章浏览阅读7.5k次,点赞5次,收藏19次。matlab结构体struct字段变量值提取_matlab读取struct类型数据中的值

Android fragment的用法_android reader fragment-程序员宅基地

文章浏览阅读4.8k次。1,什么情况下使用fragment通常用来作为一个activity的用户界面的一部分例如, 一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 – 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输_android reader fragment

FFT of waveIn audio signals-程序员宅基地

文章浏览阅读2.8k次。FFT of waveIn audio signalsBy Aqiruse An article on using the Fast Fourier Transform on audio signals. IntroductionThe Fast Fourier Transform (FFT) allows users to view the spectrum content of _fft of wavein audio signals

随便推点

Awesome Mac:收集的非常全面好用的Mac应用程序、软件以及工具_awesomemac-程序员宅基地

文章浏览阅读5.9k次。https://jaywcjlove.github.io/awesome-mac/ 这个仓库主要是收集非常好用的Mac应用程序、软件以及工具,主要面向开发者和设计师。有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章《工具武装的前端开发工程师》,于是建了这么一个仓库,持续更新作为补充,搜集更多好用的软件工具。请Star、Pull Request或者使劲搓它 issu_awesomemac

java前端技术---jquery基础详解_简介java中jquery技术-程序员宅基地

文章浏览阅读616次。一.jquery简介 jQuery是一个快速的,简洁的javaScript库,使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互 jQuery 的功能概括1、html 的元素选取2、html的元素操作3、html dom遍历和修改4、js特效和动画效果5、css操作6、html事件操作7、ajax_简介java中jquery技术

Ant Design Table换滚动条的样式_ant design ::-webkit-scrollbar-corner-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。我修改的是表格的固定列滚动而产生的滚动条引用Table的组件的css文件中加入下面的样式:.ant-table-body{ &amp;amp;::-webkit-scrollbar { height: 5px; } &amp;amp;::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box..._ant design ::-webkit-scrollbar-corner

javaWeb毕设分享 健身俱乐部会员管理系统【源码+论文】-程序员宅基地

文章浏览阅读269次。基于JSP的健身俱乐部会员管理系统项目分享:见文末!

论文开题报告怎么写?_开题报告研究难点-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏15次。同学们,是不是又到了一年一度写开题报告的时候呀?是不是还在为不知道论文的开题报告怎么写而苦恼?Take it easy!我带着倾尽我所有开题报告写作经验总结出来的最强保姆级开题报告解说来啦,一定让你脱胎换骨,顺利拿下开题报告这个高塔,你确定还不赶快点赞收藏学起来吗?_开题报告研究难点

原生JS 与 VUE获取父级、子级、兄弟节点的方法 及一些DOM对象的获取_获取子节点的路径 vue-程序员宅基地

文章浏览阅读6k次,点赞4次,收藏17次。原生先获取对象var a = document.getElementById("dom");vue先添加ref <div class="" ref="divBox">获取对象let a = this.$refs.divBox获取父、子、兄弟节点方法var b = a.childNodes; 获取a的全部子节点 var c = a.parentNode; 获取a的父节点var d = a.nextSbiling; 获取a的下一个兄弟节点 var e = a.previ_获取子节点的路径 vue