目录
SpringBoot 基本介绍
官方文档
Spring Boot 是什么?
SpringBoot 快速入门
需求/图解说明
完成步骤
创建MainApp.java SpringBoot 应用主程序
创建HelloController.java 控制器
运行MainApp.java 完成测试
快速入门小结
Spring SpringMVC SpringBoot 的关系
梳理关系
如何理解-约定优于配置
依赖管理和自动配置
依赖管理
什么是依赖管理
修改自动仲裁/默认版本号
starter 场景启动器
starter 场景启动器基本介绍
官方提供的starter
介绍
第三方starter
自动配置
自动配置基本介绍
SpringBoot 自动配置了哪些?
修改MainApp.java
如何修改默认配置
如何修改默认扫描包结构
注意
resources\application.properties 配置大全
resources\application.properties 修改配置
● 各种配置都有默认, 可以在resources\application.properties 修改,
resources\application.properties 常用配置
resources\application.properties 自定义配置
SpringBoot 在哪配置读取application.properites
基本说明
实例演示
容器功能
Spring 注入组件的注解
代码演示
创建A.java
完成测试MainApp.java
@Configuration
应用实例
创建Monster.java
创建resources\beans.xml
使用SpringBoot 的@Configuration 添加/注入组件
创建config\Cconfig\BeanConfig.java
解读
修改MainApp.java , 从配置文件/容器获取bean , 并完成测试
也可以通过Debug 来查看ioc 容器是否存在monster01 Bean 实例
@Configuration 注意事项和细节
配置类本身也是组件, 因此也可以获取, 测试修改MainApp.java
SpringBoot2 新增特性: proxyBeanMethods 指定Full 模式和Lite 模式
修改BeanConfig.java
proxyBeanMethods:代理bean的方法
修改MainApp.java完成测试
配置类可以有多个, 就和Spring 可以有多个ioc 配置文件是一个道理
创建BeanConfig2.java
修改MainApp.java完成测试
@Import
演示在SpringBoot, 如何通过@Import 来注入组件
创建Cat.java
创建Dog.java
修改BeanConfig.java 通过@Import 注入组件
修改MainApp.java完成测试
@Conditional
@Conditional 介绍
应用实例
修改beanConfig增加Dog
修改MainApp.java完成测试
增加@ConditionalOnBean注解
解读
修改MainApp.java完成测试
@ImportResource
@ImportResource 应用实例
创建新的BeanConfig3.java来测试
修改MainApp.java完成测试
配置绑定
应用实例
创建Furn.java
修改HelloController.java
启动SpringBoot 主程序,测试
配置绑定还有第2 种方式
解读
完成测试
注意事项和细节
1 官网: https://spring.io/projects/spring-boot
2 学习文档: https://docs.spring.io/spring-boot/docs/current/reference/html/
3 离线文档: spring-boot-reference.pdf
4 在线API: https://docs.spring.io/spring-boot/docs/current/api/
1 第一句话: Spring Boot 可以轻松创建独立的、生产级的基于Spring 的应用程序
2 第二句话: Spring Boot 直接嵌入Tomcat、Jetty 或Undertow ,可以"直接运行" Spring-Boot 应用程序
● 构建一个SpringBoot 项目,浏览器发送/hello 请求[http://localhost:8080/hello],响应 Hello,SpringBoot
1. 确认开发环境是jdk 8 或以上,maven 在3.5+
2. 创建maven 项目
我都博客已经介绍过了这里就不再演示 链接
3. pom.xml 引入SpringBoot 父工程和web 项目场景启动器
4.0.0
com.wyxdu
quickstart
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
2.5.3
org.springframework.boot
spring-boot-starter-web
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
//启动SpringBoot 应用程序
SpringApplication.run(MainApp.class, args);
}
}
@Controller
public class HelloController {
//返回hello,springboot
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "hello~, SpringBoot";
}
}
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
}
浏览器http://localhost:8080/hello
1. SpringBoot 比较传统的SSM 开发, 简化整合步骤, 提高开发效率
2. 简化了Maven 项目的pom.xml 依赖导入, 可以说是一键导入, 如图.
3. 引入一个spring-boot-starter-web, 到底发生了什么?
4. 内置Tomcat , 简化服务器的配置
5.等等
1. 他们的关系大概是: Spring Boot > Spring > Spring MVC
2. Spring MVC 只是Spring 处理WEB 层请求的一个模块/组件, Spring MVC 的基石是Servlet
3. Spring 的核心是IOC 和AOP, IOC 提供了依赖注入的容器, AOP 解决了面向切面编程
4. Spring Boot 是为了简化开发, 推出的封神框架(约定优于配置[COC],简化了Spring 项目
的配置流程), SpringBoot 包含很多组件/框架,Spring 就是最核心的内容之一,也包SpringMVC
5. Spring 家族,有众多衍生框架和组件例如boot、security、jpa 等, 他们的基础都是Spring
1、约定优于配置(Convention over Configuration/COC),又称按约定编程,是一种软件设计规范, 本质上是对系统、类库或框架中一些东西假定一个大众化合理的默认值(缺省值)
2、例如在模型中存在一个名为User 的类,那么对应到数据库会存在一个名为user 的表,只有在偏离这个约定时才需要做相关的配置(例如你想将表名命名为t_user 等非user 时才需要写关于这个名字的配置)
3、简单来说就是假如你所期待的配置与约定的配置一致,那么就可以不做任何配置,约定不符合期待时, 才需要对约定进行替换配置
4、约定优于配置理念【解读:为什么要搞一个约定优于配置】
约定其实就是一种规范,遵循了规范,那么就存在通用性,存在通用性,那么事情就会变得相对简单,程序员之间的沟通成本会降低,工作效率会提升,合作也会变得更加简单
- 生活中,这样的情况,大量存在..
1. spring-boot-starter-parent 还有父项目, 声明了开发中常用的依赖的版本号
2. 并且进行自动版本仲裁, 即如果程序员没有指定某个依赖jar 的版本,则以父项目指定的版本为准
1. 需求说明: 将SpringBoot mysql 驱动修改成5.1.49
2. 查看spring-boot-dependencies.pom 里面规定当前依赖的版本对应的key , 这里是
mysql.version
3. 修改springboot2\01_quickstart\pom.xml 重写配置, 当更新Maven 时,就依赖到新的
mysql 驱动.
4.0.0
com.wyxdu
quickstart
1.0-SNAPSHOT
spring-boot-starter-parent
org.springframework.boot
2.5.3
5.1.49
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
1. 开发中我们引入了相关场景的starter,这个场景中所有的相关依赖都引入进来了,比如我们做web 开发引入了,该starter 将导入与web 开发相关的所有包
2. 依赖树: 可以看到spring-boot-starter-web ,帮我们引入了spring-webmvc,spring-web开发模块,还引入了spring-boot-starter-tomcat 场景,spring-boot-starter-json 场景,这些场景下面又引入了一大堆相关的包,这些依赖项可以快速启动和运行一个项目,提高开发效率.
3. 所有场景启动器最基本的依赖就是spring-boot-starter , 前面的依赖树分析可以看到,这个依赖也就是SpringBoot 自动配置的核心依赖
地址: https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build systems.starters
1. 在开发中我们经常会用到spring-boot-starter-xxx ,比如spring-boot-starter-web,该场景是用作web 开发,也就是说xxx 是某种开发场景。
2. 我们只要引入starter,这个场景的所有常规需要的依赖我们都自动引入。
3. SpringBoot2 支持的所有场景如下:
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-sys
tems.starters
1. SpringBoot 也支持第三方starter
2. 第三方starter 不要从spring-boot 开始,因为这是官方spring-boot 保留的命名方式的。第三方启动程序通常以项目名称开头。例如,名为thirdpartyproject 的第三方启动程序项目通常被命名为thirdpartyproject-spring-boot-starter。
3. 也就是说:xxx-spring-boot-starter 是第三方为我们提供的简化开发的场景启动器
1. 小伙伴还记得否,前面学习SSM 整合时,需要配置Tomcat 、配置SpringMVC、配置如何扫描包、配置字符过滤器、配置视图解析器、文件上传等[如图],非常麻烦。而在SpringBoot 中,存在自动配置机制,提高开发效率
2. 简单回顾以前SSM 整合的配置
1. 自动配置Tomcat
2. 自动配置SpringMVC
3. 自动配置Web 常用功能: 比如字符过滤器, 提示: 通过获取ioc 容器,查看容器创建的组件来验证,
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
//查看容器里面的组件
String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
-------更加直接查看的方式-------
4. 自动配置: 默认扫描包结构!!! , 官方文档:
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.structuring-your-code.using-the-default-package
1. 需求:要求能扫描com.hspedu 包下的HiController.java 应该如何处理?
2. 创建: springboot2\01_quickstart\src\main\java\com\wyxedu\HiController.java, 并测试,这时是访问不到的.
@Controller
public class HiController {
@RequestMapping("/hi")
@ResponseBody
public String hi(){
return "hi~, spring boot";
}
}
3. 修改MainApp.java, 增加扫描的包, 并完成测试.
@SpringBootApplication:表示这是一个springboot应用/项目
@SpringBootApplication(scanBasePackages="com.wyxdu")
解读:scanBasePackages="com.wyxdu"指定springboot要扫描的包和子包
如果有多个包,可以这样scanBasePackages={"com.wyxdu","xxx.yyy.zzz"}
@SpringBootApplication(scanBasePackages = "com.wyxdu")
public class MainApp {}
SpringBoot 项目最重要也是最核心的配置文件就是application.properties,
所有的框架配置都可以在这个配置文件中说明- 地址: https://blog.csdn.net/pbrlovejava/article/details/82659702
application.properties 文件我们可以手动创建
#默认server.port=8080
server.port=10000
#比如: 默认spring.servlet.multipart.max-file-size=1MB
#该属性可以指定springboot 上传文件大小的限制
#默认配置最终都是映射到某个类上,比如这里配置会映射到MultipartProperties
#把光标放在该属性,ctrl+b 就可以定位该配置映射到的类
spring.servlet.multipart.max-file-size=10MB
因为有点多所以在宁外一篇博客 链接
● 还可以在properties 文件中自定义配置,通过@Value("${}")获取对应属性值
application.properties 文件
my.website=https://www.baidu.com-
//某个Bean
@Value("${my.website}")
private String bdUrl;
1、打开ConfigFileApplicationListener.java , 看一下源码
2、测试, 如果我们把application.properties 放在resources\config 目录下, 你会发现依然
是管用的.
3、测试完毕, 记得把恢复到原来的位置.
1. 自动配置遵守按需加载原则:也就是说,引入了哪个场景starter 就会加载该场景关联的jar 包,没有引入的starter 则不会加载其关联jar
2. SpringBoot 所有的自动配置功能都在spring-boot-autoconfigure 包里面
3. 在SpringBoot 的自动配置包, 一般是XxxAutoConfiguration.java, 对应XxxxProperties.java, 如图
1. 以MultipartProperties , MultipartAutoConfiguration 和application.properties 来说明
@Component、@Controller、@Service、@Repository
说明: 这些在Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件
@Repository
public class A {
}
//演示Spring中传统的注解依然可以使用 @Controller @Service @Repository 等.
A aBean = ioc.getBean(A.class);
System.out.println("aBean--" + aBean);
● @Configuration 应用实例需求
: 演示在SpringBoot, 如何通过@Configuration 创建配置类来注入组件
● 回顾传统方式如何通过配置文件注入组件
public class Monster {
private Integer id;
private String name;
private Integer age;
private String skill;
public Monster(Integer id, String name, Integer age, String skill) {
this.id = id;
this.name = name;
this.age = age;
this.skill = skill;
}
public Monster() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
@Override
public String toString() {
return "Monster{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", skill='" + skill + '\'' +
'}';
}
}
完成测试MainApp.java
//--演示在springboot 项目,依然可以使用spring的配置bean/注入bean/获取bean方式 start====
ApplicationContext ac =
new ClassPathXmlApplicationContext("beans.xml");
Monster monster03 = ac.getBean("monster03", Monster.class);
System.out.println("monster03--" + monster03);
@Configuration 标识这是一个配置类, 等价于配置文件
程序员可以通过@Bean 注解注入bean对象到容器
当一个类被 @Configuration 标识,该类-Bean 也会注入容器
@Configuration
public class BeanConfig {
/**
* 解读
* 1. @Bean : 给容器添加组件, 就是Monster bean
* 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
* 3. Monster : 注入类型, 注入bean的类型是Monster
* 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息
* 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw
* 6. 默认是单例注入
* 7. 通过 @Scope("prototype") 可以每次返回新的对象,就多例.
*/
//@Bean(name = "monster_nmw")
@Bean
//@Scope("prototype")
public Monster monster01() {
return new Monster(200, "牛魔王", 500, "疯魔拳");
}
// ===演示 @Configuration start ====
Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);
System.out.println("monster01--" + monster01 + " " + monster01.hashCode());
System.out.println("monster02--" + monster02 + " " + monster02.hashCode());
beanDefinitionMap, 只是存放了bean 定义信息, 真正存放Bean 实例的在singleonObjectis 的Map 中, 对于非单例,是每次动态反射生成的实例
//===演示 配置类-bean也会注入容器 start ====
BeanConfig bean = ioc.getBean(BeanConfig.class);
System.out.println("bean--" + bean);
//===演示 配置类-bean也会注入容器 end ====
(1) Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】
(2) Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式】
(3) 特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
(4) 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模
(5) Lite模 也称为轻量级模式,因为不检测依赖关系,运行速度快
@Configuration(proxyBeanMethods = false)
public class BeanConfig {.....}
@SpringBootApplication(scanBasePackages = "com.wyxdu")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
//===演示@Configuration(proxyBeanMethods = xxx) start
//1. 先得到BeanConfig组件
BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
Monster monster_01 = beanConfig.monster01();
Monster monster_02 = beanConfig.monster01();
System.out.println("monster_01-" + monster_01 + " " + monster_01.hashCode());
System.out.println("monster_02-" + monster_02 + " " + monster_02.hashCode());
//特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法
//1. 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);
System.out.println("monster01-" + monster01 + " " + monster01.hashCode());
System.out.println("monster02-" + monster02 + " " + monster02.hashCode());
//===演示@Configuration(proxyBeanMethods = xxx) end
}
@Configuration
public class BeanConfig2 {
@Bean
public Monster monster02() {
return new Monster(800,"蚂蚁精",80,"吃小昆虫");
}
}
@SpringBootApplication(scanBasePackages = "com.wyxdu")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
//===测试可以有多个配置类 start
Monster monster02 = ioc.getBean("monster02", Monster.class);
Monster monster01 = ioc.getBean("monster01", Monster.class);
System.out.println("monster02--" + monster02);
System.out.println("monster01--" + monster01);
//===测试可以有多个配置类 end
}
public class Cat {
}
public class Dog {
}
解读
1. @Import 代码 可以看到,可以指定 class的数组, 可以注入指定类型的Bean
public @interface Import {
Class>[] value()}
2. 通过@Import 方式注入了组件, 默认组件名字/id就是对应类型的全类名
@Import({Dog.class, Cat.class})
@Configuration
public class BeanConfig {}
//===测试@Import 使用 start
Dog dogBean = ioc.getBean(Dog.class);
Cat catBean = ioc.getBean(Cat.class);
System.out.println("dogBean--" + dogBean);
System.out.println("catBean--" + catBean);
//===测试@Import 使用 end
1. 条件装配:满足Conditional 指定的条件,则进行组件注入
2. @Conditional 是一个根注解,下面有很多扩展注解
1. 要求: 演示在SpringBoot, 如何通过@ConditionalOnBean 来注入组件
2. 只有在容器中有name = monster_nmw 组件时,才注入dog01, 代码如图
@Bean
public Dog dog01() {
return new Dog();
}
先测试下,当前是否能注入dog01
@SpringBootApplication(scanBasePackages = "com.wyxdu")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
Dog dog01 = ioc.getBean("dog01", Dog.class);
System.out.println("dog01--" + dog01);
}
1. @ConditionalOnBean(name = "monster_nmw") 表示
2. 当容器中有一个Bean , 名字是monster_nmw (类型不做约束), 就注入dog01这个Dog bean
3. 如果没有 名字是monster_nmw Bean 就不注入dog01这个Dog bean
4. 还有很多其它的条件约束注解,可以自己测试
5. @ConditionalOnMissingBean(name = "monster_nmw") 表示在容器中, 没有 名字/id 为 monster_nmw 才注入dog01这个Bean
6. @ConditionalOnBean(name = "monster_nmw") 也可以放在配置类 表示对该配置类的所有要注入的组件,都进行条件约束.
@Bean
/**
* 解读
* 1. @ConditionalOnBean(name = "monster_nmw") 表示
* 2. 当容器中有一个Bean , 名字是monster_nmw (类型不做约束), 就注入dog01这个Dog bean
* 3. 如果没有 名字是monster_nmw Bean 就不注入dog01这个Dog bean
* 4. 还有很多其它的条件约束注解,小伙伴可以自己测试
*
* 5. @ConditionalOnMissingBean(name = "monster_nmw") 表示在容器中,
* 没有 名字/id 为 monster_nmw 才注入dog01这个Bean
*
* 6. @ConditionalOnBean(name = "monster_nmw") 也可以放在配置类
* 表示对该配置类的所有要注入的组件,都进行条件约束.
*
*/
@ConditionalOnBean(name = "monster_nmw")
//@ConditionalOnMissingBean(name = "monster_nmw")
public Dog dog01() {
return new Dog();
}
@SpringBootApplication(scanBasePackages = "com.wyxdu")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
//===演示 @ConditionalOnBean 使用 start ====
Dog dog01 = ioc.getBean("dog01", Dog.class);
System.out.println("dog01--" + dog01);
//===演示 @ConditionalOnBean 使用 end ====
}
作用:原生配置文件引入, 也就是可以直接导入Spring 传统的beans.xml ,可以认
为是SpringBoot 对Spring 容器文件的兼容.
需求: 将beans.xml 导入到BeanConfig.java 配置类, 并测试是否可以获得beans.xml注入/配置的组件
使用@ImportResource 导入beans.xml
@Configuration
//导入beans.xml - 就可以获取到beans.xml 中配置bean
@ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})
public class BeanConfig3 {
}
@SpringBootApplication(scanBasePackages = "com.wyxdu")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc =
SpringApplication.run(MainApp.class, args);
//演示@ImportResource 使用 start===
Monster monster04 = ioc.getBean("monster04", Monster.class);
System.out.println("monster04-" + monster04);
System.out.println("monster04 bean 是否存在-" + ioc.containsBean("monster04"));
//演示@ImportResource 使用 end===
}
一句话:使用Java 读取到SpringBoot 核心配置文件application.properties 的内容,
并且把它封装到JavaBean 中
1. 需求: 将application.properties 指定的k-v 和JavaBean 绑定
#设置Furn的属性k-v
#前面的 furn01 是用于指定/区别不同的绑定对象, 这样可以再绑定Furn bean属性值时
#通过furn01 前缀进行区分
#furn01.id 中的id 就是你要绑定的 Furn bean的属性名
furn01.id=100
furn01.name=TV~~\u7535\u89c6\u673a
furn01.price=1000.9
@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
@Autowired
Furn furn;
@RequestMapping("/furn")
@ResponseBody
public Furn furn(){
return furn;
}
也给演示下, 完成测试,效果一样, 注意: 注销
@Component 需要在BeanConfig.java( 说明: 也可以是其它配置类) 配置
@EnableConfigurationProperties(Furn.class), 否则会提示错误
1、开启Furn配置绑定功能
2、把Furn组件自动注册到容器中
@EnableConfigurationProperties({Furn.class})
public class BeanConfig {}
1. 如果application.properties 有中文, 需要转成unicode 编码写入, 否则出现乱码
#设置属性k-v
furn01.id=100
furn01.name=\u4f60\u597d
furn01.price=45678.9
2. 使用@ConfigurationProperties(prefix = "furn01") 会提示如下信息, 但是不会影响使用
3. 解决@ConfigurationProperties(prefix = "furn01") 提示信息, 在pom.xml 增加依赖, 即可
org.springframework.boot
spring-boot-configuration-processor
true
后面我们在来分析一下boot的底层实现机制。