源码地址
# 一、Spring与SpringBoot
1. Spring生态Springboot+Spring Framework+Spring Data+Spring Cloud+Spring Security…
覆盖了:
- web开发、数据访问、安全控制、分布式、消息服务、移动开发、批处理…
Spring5重大升级:
- 响应式编程:占用少量资源来处理大规模并发
- 内部源码设计改变
适配器设计模式:A接口有(1,2,3,4,5方法),B适配器实现A。C类继承B(重写1,2,3方法),D类继承B重写(4,5方法)
基于Java8的一些新特性,如:提供了接口默认实现。Spring5重新设计源码架构。
2. SpringBoot特点2.1 优点特点:能快速创建出生产级别的Spring应用,整合Spring其他框架
-
创建独立Spring应用
-
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
-
Provide opinionated ‘starter’ dependencies to simplify your build configuration
- 自动starter依赖,简化构建配置
-
Automatically configure Spring and 3rd party libraries whenever possible
- 自动配置Spring以及第三方功能
-
提供生产级别的监控、健康检查及外部化配置
-
无代码生成、无需编写XML
-
SpringBoot是整合Spring技术栈的一站式框架
-
SpringBoot是简化Spring技术栈的快速开发脚手架
- 人称版本帝,迭代快,需要时刻关注变化
- 封装太深,内部原理复杂,不容易精通
- 微服务是一种架构风格,将大型软件拆分为小服务独立部署
- 一个应用拆分为一组小型服务
- 每个服务运行在自己的进程内,也就是可独立部署和升级
- 服务之间使用轻量级HTTP交互
- 服务围绕业务功能拆分
- 可以由全自动部署机制独立部署
- 去中心化,服务自治。服务可以使用不同的语言、不同的存储技术。
分布式的困难:
- 远程调用:各个服务之间通过http交互
- 服务发现:相同服务被部署在不同机器上,需要发现正常运行服务
- 负载均衡:相同服务被部署在不同机器上,选择调用哪个
- 服务容错:服务出现异常时处理
- 配置管理:所有服务配置放在配置中心中,只需修改一处
- 服务监控:监控服务健康状况,cpu占用等
- 链路追踪:追踪服务间互相调用
- 日志管理:分布式日志管理
- 任务调度:并行还是串行,或者某一个先触发
- …
分布式的解决:
- SpringBoot(开发各种微服务应用)+ SpringCloud(整合)
即原生应用如何上云。 Cloud Native
上云的困难:
- 服务自愈:C服务部署两台服务器,有一天一台炸了后,在其他服务器拉起一份C
- 弹性伸缩:流量高峰时,C服务能自动扩充几台;高峰过后自动下线
- 服务隔离:同台服务器上部署C、D、E服务,互不影响
- 自动化部署:将微服务部署到云平台
- 灰度发布:B服务更新2.0后,将某几台机子换成新版本,经过长时间迭代后发现没问题再把老版本逐一下线
- 流量治理:限制每台服务器的流量
- …
上云的解决:
4. SpringBoot官方文档-
Spring Boot官网
-
查看版本新特性
-
官方文档架构
- Maven配置文件
新添内容:
nexus-aliyun central Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public jdk-1.8 true 1.8 1.8 1.8 1.8
需求:浏览发送/hello请求,响应 “Hello,Spring Boot 2”
1.创建maven工程
2.引入依赖
org.springframework.boot spring-boot-starter-parent 2.3.4.RELEASE org.springframework.boot spring-boot-starter-web
3.创建主程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
4.编写业务
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(){
return "Hello, Spring Boot 2!";
}
}
5.运行&测试
- 运行MainApplication类
- 浏览器输入http://localhost:8080/hello,将会输出Hello, Spring Boot 2!
- 打印日志
- @slf4j注解类
- log.info(“要检测的内容:username={}”,username);
设置配置:
maven工程的resource文件夹中创建application.properties文件。
# 设置端口号 server.port=8888
更多配置信息
6.打包部署
在pom.xml添加:
org.springframework.boot spring-boot-maven-plugin
- 在IDEA的Maven插件上点击运行 clean 、package,把helloworld工程项目的打包成jar包,
打包好的jar包被生成在helloworld工程项目的target文件夹内。
-
用cmd运行java -jar boot-01-helloworld-1.0-SNAPSHOT.jar,既可以运行helloworld工程项目。
-
将jar包直接在目标服务器执行即可。
a> 父项目做依赖管理,后续引入依赖时不需要加版本号
依赖管理:org.springframework.boot spring-boot-starter-parent 2.3.4.RELEASE
源码中父项目如下:
org.springframework.boot spring-boot-dependencies 2.3.4.RELEASE
它几乎声明了所有开发中常用的依赖的默认版本号,自动版本仲裁机制
b> 开发导入 spring-boot-starter-场景启动器
- 只要引入starter,这个场景的所有常规需要的依赖我们都自动引入,如spring-boot-starter-web
- 更多SpringBoot所有支持的场景;见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
所有场景启动器最底层的依赖org.springframework.boot spring-boot-starter 2.3.4.RELEASE compile
c> 导入依赖时无需关注版本号,自动版本仲裁
- 引入依赖默认都可以不写版本
- 引入非版本仲裁的jar,要写版本号。
org.springframework.boot spring-boot-starter-web mysql mysql-connector-java
d> 可以修改默认版本号
- 查看spring-boot-dependencies里面规定当前依赖的版本用的 key。
- 在当前项目里面重写配置pom.xml,如下面的代码。
2. 自动配置8.0.26
组件在容器中有,就会生效:
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
- 自动配好Tomcat (由spring-boot-starter-web引入)
- 引入Tomcat依赖。
- 配置Tomcat
org.springframework.boot spring-boot-starter-tomcat 2.3.4.RELEASE compile
-
自动配好SpringMVC(由spring-boot-starter-web引入)
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用组件(DispatcherServlet,ViewResolver, multipartResolver)
-
自动配好Web常见功能,如:字符编码问题
- SpringBoot帮我们配置好了所有web开发的常见场景
-
默认的包结构
- 无需以前的包扫描配置,主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 想要改变扫描路径
- @SpringBootApplication(scanBasePackages=“com.zju”)
- @ComponentScan 指定扫描路径
@SpringBootApplication
==等同于==
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.zju.boot")
- 各种配置拥有默认值
- 配置文件application.properties的值最终会绑定每个类上,如:MultipartProperties这个类会在容器中创建对象
- 想要修改配置只需要在配置文件中设置
- 按需加载所有自动配置项
- SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
- 有非常多的starter,引入了哪些场景这个场景的自动配置才会开启
- …
组件的循环依赖特性,必须是单实例
-
配置类本身也是组件
-
配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
-
Full模式(proxyBeanMethods = true):保证每个@Bean方法被调用多少次返回的组件都是单实例的
- 配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)
-
Lite模式(proxyBeanMethods = false):每个@Bean方法被调用多少次返回的组件都是新创建的
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
//Tomcat中组件为
Spring中基本标签
它们是Spring的基本标签,在Spring Boot中并未改变它们原来的功能
-
@Bean:表示方法返回对象,然后对象交给IOC管理
-
@Component:普通的注解
-
@Controller:web层
-
@Service:业务逻辑层以及Service层
-
@Repository:dao层即持久层
-
@ComponentScan:扫描包
@Import({User.class, DBHelper.class,…})自动从类中的无参构造函数创建一个实例注册到IOC容器中
【注意】IOC容器中默认组件的名字id就是全类名,如 User 类就是:com.zju.boot.bean.User
@Import({User.class, DBHelper.class})
public class MyConfig {
}
@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
用@ConditionalOnMissingBean举例说明:
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = "tom")//没有tom名字的Bean时,MyConfig类的Bean才能生效。
public class MyConfig {
@Bean
public User user01(){
User zhangsan = new User("zhangsan", 18);
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom22")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
boolean tom = run.containsBean("tom");
System.out.println("容器中Tom组件:"+tom);//false
boolean user01 = run.containsBean("user01");
System.out.println("容器中user01组件:"+user01);//true
boolean tom22 = run.containsBean("tom22");
System.out.println("容器中tom22组件:"+tom22);//true
}
3.2 原生配置文件引入
@ImportResource导入Spring配置文件
使用场景:比如,公司使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource粉墨登场。
beans.xml:
使用方法:将注解加到配置类中
@ImportResource("classpath:beans.xml")
public class MyConfig {
...
}
- classpath:
spring.banner.image.location=classpath:banner.jpg
3.3 属性值绑定classpath:只会到你的class路径中查找文件
读取properties文件中的内容,并且把它封装到JavaBean中,以供随时使用
方法一:
@ConfigurationProperties + @Component在实体类中配置@ConfigurationProperties
配置文件application.properties中
mycar.brand=BYD mycar.price=100000
//只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
...
}
@RestController
public class HelloController {
@Autowired
Car car;//根据类型属性注入
@RequestMapping("/car")
public Car car(){
return car;
}
}
方法二:
@EnableConfigurationProperties + @ConfigurationProperties应用场景,引用第三方包中类没有配置@Component注解
-
开启Car属性配置绑定功能
-
把这个Car这个组件自动注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}
4. 自动装配原理入门
4.1 引导加载自动配置类
@SpringBootConfigurationSpring Boot应用启动类:@SpringBootApplication= @SpringBootConfiguration + @EnableAutoConfiguration +@ComponentScan
@Configuration代表当前是一个配置类。
@ComponentScan@EnableAutoConfiguration指定要扫描哪些包
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
- @AutoConfigurationPackage自动包规则原理
自动配置包?指定了默认的包规则,即mainApplication所在包路径
@Import(AutoConfigurationPackages.Registrar.class)//给容器中导入一个组件
public @interface AutoConfigurationPackage {
...
}
- 利用Registrar给容器中批量导入一系列组件
- 将指定的一个包下的所有组件导入进MainApplication所在包下,解释了SpringBoot在mainApplication所在包下类中注解能被识别
- @Import(AutoConfigurationImportSelector.class)初始加载自动配置类
- 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
- 调用List
configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类 - 利用工厂加载 Map
> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件 - 从META-INF/spring.factories位置来加载一个文件。
- 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
- spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
# 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类127个 # spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration, org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration, org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, ...4.2 按需开启自动配置项
虽然我们127个场景的所有自动配置类启动的时候默认全部加载,
但是xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置
如AopAutoConfiguration类:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = "auto",
havingValue = "true",
matchIfMissing = true
)
public class AopAutoConfiguration {
public AopAutoConfiguration() {
}
...
}
4.3 定制化修改自动配置
以autoconfigure—web—servlet—DispatcherServletAutoConfiguration—multipartResolver为例
//文件上传解析器自动配置
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。此时容器中有MultipartResolver但命名不规范。
//SpringMVC中命名为multipartResolver。防止有些用户配置的文件上传解析器命名不符合规范。
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;//给容器中加入了文件上传解析器;
}
- SpringBoot默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先
4.4 总结自动装配流程以ChracterEncoding为例
- SpringBoot先加载所有的自动配置类 xxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值(xxxProperties里面读取,xxxProperties和配置文件进行了绑定)
- 生效的配置类就会给容器中装配很多组件(@Bean)
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置(以用户自己配置优先)
- 用户直接自己==@Bean替换底层的组件==
- 用户去看这个组件是获取的配置文件什么值就去application.properties修改配置文件
xxxAutoConfiguration加载自动配置类 —> 装配组件 —> xxxProperties里面拿值属性值 ----> application.properties自定义属性值
4.5 Springboot开发最佳实践 a> 应用如何编写因此,修改配置文件即为修改整合场景的配置,配置文档或者查看底层源码
- 引入场景依赖
- 参考官方文档,xxx-starter
- 查看自动配置了哪些(选做)
- 配置文件中debug=true开启自动配置报告,可以查看生效配置
- Negative matches(不生效)
- Positive matches(生效)
- 配置文件中debug=true开启自动配置报告,可以查看生效配置
- 是否需要修改配置,改变默认行为
- 参照文档修改配置项
- 参考官方文档 xxxproperties
- 自定义加入或者替换组件
- @Bean、@Component…
- 自定义器 XXXXXCustomizer
- 参照文档修改配置项
Lombok用标签方式代替构造器、getter/setter、toString()等鸡肋代码。
-
安装Lombok插件
-
spring boot已经管理Lombok,引入依赖:
org.projectlombok lombok
- 在实体类加上注解
@NoArgsConstructor
//@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class User {
private String name;
private Integer age;
private Pet pet;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
- 简化日志开发,可以相当于sout使用
@Slf4j
@RestController
public class HelloController {
@RequestMapping("/Hello/{username}")
public String HelloMapping(@PathVariable("username") String username){
log.info("请求进来了");
return "Hello, wz "+username;
}
}
c> dev-tools
实现热部署,自动重启
- 添加依赖:
org.springframework.boot spring-boot-devtools true
在IDEA中,项目或者页面修改以后:Build project(Ctrl+F9)。
d> Spring InitailizrSpring Initailizr是创建Spring Boot工程向导,搭建好基础架构
在IDEA中,菜单栏New -> Project -> Spring Initailizr
四、配置文件 1. propertiesapplication.properties中写配置文件
2. yaml基本语法一种标记语言,非常适合用来做以数据为中心的配置文件,替代xml
- key: value;kv之间有空格
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注释
- 字符串无需加引号,如果要加,单引号’'、双引号""表示字符串内容会被 转义、不转义
- 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
- 对象:键值对的集合。map、hash、object
#行内写法:类似于json
k: {k1: v1,k2: v2,k3: v3}
#或
k:
k1: v1
k2: v2
k3: v3
- 数组:一组按次序排列的值。array、list、queue、set
#行内写法:类似于json k: [v1,v2,v3] #或者 k: - v1 - v2 - v3实例
@Data
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List animal;
private Map score;
private Set salarys;
private Map> allPets;
}
@Data
public class Pet {
private String name;
private Double weight;
}
- 用yaml表示以上对象(properties>yml>yaml),配置一般是为了初始化使用的
person:
username: fkd
boss: true
birth: 2022/4/21 21:55:00
age: 23
pet: {name: wz,weight: 23}
interests: [篮球,足球]
animal: [猫,够,兔子]
score: {math: 80, English: 90}
salaries: [32000,43000,31000]
allPets: {sick: [{name: wz,weight: 20},{name: fkd,weight: 22}],healthy:[{name: sk,weight: 30}]}
3. 配置提示
自定义的类和配置文件绑定一般没有提示。若要提示,添加如下依赖:
org.springframework.boot spring-boot-configuration-processor true
pet;
private String[] interests;
private List animal;
private Map
private Set salarys;
private Map
}
@Data
public class Pet {
private String name;
private Double weight;
}
- 用yaml表示以上对象(properties>yml>yaml),配置一般是为了初始化使用的
```yaml
person:
username: fkd
boss: true
birth: 2022/4/21 21:55:00
age: 23
pet: {name: wz,weight: 23}
interests: [篮球,足球]
animal: [猫,够,兔子]
score: {math: 80, English: 90}
salaries: [32000,43000,31000]
allPets: {sick: [{name: wz,weight: 20},{name: fkd,weight: 22}],healthy:[{name: sk,weight: 30}]}
3. 配置提示
自定义的类和配置文件绑定一般没有提示。若要提示,添加如下依赖:
org.springframework.boot spring-boot-configuration-processor true



