1、特此申明:此文档是观看雷丰阳老师的视频跟着敲出来的,紧作为学习文档记录在此。
2、雷丰阳老师的文档请参考链接: SpringBoot2核心技术与响应式编程 .
3、雷丰阳老师的讲解视频参考链接: 【2021版最新SpringBoot2_权威教程】.
3、如有侵权联系作者本人,私了本人删除。
4、链接: 官方文档.
一、基础入门
1.1了解自动配置原理
-
开发导入starter场景启动器
1、见到很多spring-boot-starter-* ;*就是某种场景 2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入 3、SpringBoot所有支持的场景 https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters 4、见到 *-spring-boot-starter;第三方为我们提供的简化开发的场景启动器 5、所有场景启动器最底层的依赖 <artifactId>spring-boot-starter</artifactId>
-
无需关注版本号,自动版本仲裁
1、引入依赖默认都可以不引入版本号 2、引入非版本仲裁的jar,需要写版本号。
-
可自定义修改版本号
1、查看spring-boot-dependencies里面规定当前依赖的版本用的Key。 2、在当前项目里面重写这个配置 以mysql为列: <properties> <mysql.version>5.1.43</mysql.version> </properties>
1.2自动配置
-
自动配置好Tomcat
- 引入Tomcat依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.5.2</version> <scope>compile</scope> </dependency>
-
自动配置号SpringMVC
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用功能(组件)
-
自动配置号Web常见功能,如:字符编码问题
- SpringBoot帮我们配置好了所有Web开发的常见场景
-
默认的包结构
-
主程序错在的包及其下面的所有子包里面的组件都会被默认扫描进来
-
无需以前的包扫描配置
-
想要改变扫描路径:@SpringBootApplication(scanBasePackages=“com.lxm”) ;com.lxm 为包名
-
或者==@ComponentScan==扫描指定路径
@SpringBootApplication 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(com.lxm)
-
-
-
各种配置拥有默认值
- 默认配置最终都是映射到MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
-
按需加载所有自动配置
- 非常多的starter
- 引入了哪些场景这个场景自动配置才会开启
- SpringBoot所有的自动配置功能都在spring-boot-autoconfigure
2.容器功能
2.1、组件添加
1. @Configuration
2.1、组件添加
-
@Configuration
-
基本使用
-
Full模式与Lite模式
-
Full(proxyBeanMethods = true)
【保存每个@Bean方法被调用多少次返回的组件都是单实例的】
-
Lite(proxyBeanMethods = false)
【每个@Bean方法被调用多少次返回的组件都是新创建的】
-
配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
-
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
-
-
@Configuration使用实例代码如下:
======================@Configuration使用实例================================================= package com.example.springbootdemo.boot.config; import com.example.springbootdemo.boot.bean.Pet; import com.example.springbootdemo.boot.bean.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /* * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实列的 * 2、配置类本省也是组件 * 3 、proxyBeanMethods:代理bean的方法 * Full(proxyBeanMethods = true) 【保存每个@Bean方法被调用多少次返回的组件都是单实例的】 * Lite(proxyBeanMethods = false) 【每个@Bean方法被调用多少次返回的组件都是新创建的】 * 组件依赖必须使用Full模式默认,其他默认是Lite模式 * 最佳实战: * 1、配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断。 * 2、配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式。 * */ //告诉SpringBoot这是一个配置类 == 配置类 @Configuration(proxyBeanMethods = false) public class MyConfig { /** * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象 * @return */ @Bean//给容器中添加组件,以方法名作为组件的ID。返回类型就是组件类型。返回值,就是组件在容器中的实列。 public User user01(){ User zhansan = new User("张三",18); //user组件依赖了Pet组件 :proxyBeanMethods = true 就不会报错 zhansan.setPet(tomcatPet()); return zhansan; } @Bean("tom")//重命名组件名为tom public Pet tomcatPet(){ return new Pet("tomcat"); } }
============================@Configuration测试代码实列如下:================================= /** * 主程序类;主配置类 * * @SpringBootApplication:这是一个SpringBoot应用 * */ @SpringBootApplication() public class SpringBootDemoApplication { public static void main(String[] args) { //1.返回我们的IOC容器 ConfigurableApplicationContext ioc= SpringApplication.run(SpringBootDemoApplication.class, args); //2.查看荣日里面的组件 String[] names= ioc.getBeanDefinitionNames(); for (String name: names) { System.out.println(name); } //3、从容器中获取组件, Pet tom01 = ioc.getBean("tom",Pet.class); Pet tom02 = ioc.getBean("tom",Pet.class); System.out.println("组件:"+(tom01==tom02)); MyConfig bean = ioc.getBean(MyConfig.class); System.out.println(bean); //4、如果@Configuration(proxyBeanMethods = true) 代理对象调用方法。SpringBoot总会检查这个组件是否在容器中。 //保持组件单实例 User user = bean.user01(); User user01 = bean.user01(); System.out.println(user==user01); User user02 = ioc.getBean("user01",User.class); Pet pet = ioc.getBean("tom",Pet.class); System.out.println("用户的宠物:"+(user02.getPet()==pet)); //5、获取组件 String[] beanNameForType = ioc.getBeanNamesForType(User.class); System.out.println("==============================="); for (String s:beanNameForType) { System.out.println(s); } DBHelper bean1 = ioc.getBean(DBHelper.class); System.out.println(bean1); } }
-
2. @Bean、@Component、@Controller、@Service、@Repository
3. @ComponentScan、@Import
/*
*4、@Import({User.class, DBHelper.class})
* 给容器中自动创建这两个类型的组件,默认组件的名字就是全类名:com.example.springbootdemo.boot.bean.User
* */
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置类
public class MyConfig {
}
@Import高级用法
/**
* 给容器中注册组件:
* 1、包扫描+组件标注注解(@Component、@Controller、@Service、@Repository)
局限:自己写的类
*2、@Bean :[导入的三方包里面的组件]
*3、@Import :[快速给容器导入一个组件]
1、@Import(要导入到容器中的组件):容器中就会自动注册这个组件,id默认是全类名;
2、ImportSelector :返回需要导入的组件的全类名数组
3、ImportBeanDefinitionRegistrar:手动注册bean到容器中
*4、使用Spring提供的FactoryBean(工厂Bean);
1、默认获取到的是工厂bean调用getObject创建的对象
2、要获取工厂Bean本身,我们需要给id前面加一个&
*/
ImportSelector :返回需要导入的组件的全类名数组
=============创建一个MyImportSelectors实现ImportSelector=============
package com.example.springbootdemo.boot.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.function.Predicate;
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector
{
//返回值,就是导入容器中的组件全类名
//AnnotationMetadata :当前标志@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//方法不要返回NULL值,可以返回一个空的数组
return new String[]{"com.example.springbootdemo.boot.bean.Bule","com.example.springbootdemo.boot.bean.Rad"};
}
@Override
public Predicate<String> getExclusionFilter() {
return null;
}
}
========================添加Bule类===================================
package com.example.springbootdemo.boot.bean;
public class Bule {
}
==========================添加Red类==================================
package com.example.springbootdemo.boot.bean;
public class Red {
}
====================@Import添加MyImportSelectors====================
@Import({User.class, DBHelper.class,MyImportSelector.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置类
public class MyConfig {
}
======================测试容器中是否能拿到Bule、Rad组件===============
/**
* 主程序类;主配置类
*
* @SpringBootApplication:这是一个SpringBoot应用
*
*/
@SpringBootApplication()
public class SpringBootDemoApplication {
public static void main(String[] args) {
//1.返回我们的IOC容器
ConfigurableApplicationContext ioc= SpringApplication.run(SpringBootDemoApplication.class, args);
Bule bean3 = ioc.getBean(Bule.class);
Red bean4 = ioc.getBean(Red.class);
System.out.println("Bule:"+bean3);
System.out.println("Rad:"+bean4);
}
}
=========================控制台输出结果======================================
Bule:com.example.springbootdemo.boot.bean.Bule@682c1e93
Rad:com.example.springbootdemo.boot.bean.Red@27068a50
ImportBeanDefinitionRegistrar:手动注册bean到容器中
========================创建Yellow类=====================================
package com.example.springbootdemo.boot.bean;
public class Yellow {
}
============创建MyImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar============
public class MyImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类:
* 把所有需要添加到容器中的bean,调用BeanDefinitionRegistry.registerBeanDefinition 手工注册进来
*
* @param importingClassMetadata
* @param registry
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Boolean definition = registry.containsBeanDefinition("com.example.springbootdemo.boot.bean.Bule");
Boolean definition2 = registry.containsBeanDefinition("com.example.springbootdemo.boot.bean.Red");
if (definition && definition2){//容器中有这两个时,就添加
//指定Bean定义信息,(Bean的类型,Bean作用域....)
RootBeanDefinition beanDefinition = new RootBeanDefinition(Yellow.class);
//注册一个Bean,指定bean名
registry.registerBeanDefinition("Yellow",beanDefinition);
}
}
}
===================@Import添加MyImportDefinitionRegistrar=============================
@Import({User.class, DBHelper.class,MyImportSelector.class,MyImportDefinitionRegistrar.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置类
public class MyConfig {
}
==============================================测试======================================
/**
* 主程序类;主配置类
*
* @SpringBootApplication:这是一个SpringBoot应用
*
*/
@SpringBootApplication()
public class SpringBootDemoApplication {
public static void main(String[] args) {
//1.返回我们的IOC容器
ConfigurableApplicationContext ioc= SpringApplication.run(SpringBootDemoApplication.class, args);
//@Import 高级用法 实现ImportBeanDefinitionRegistrar 手动注册bean
Yellow bean5 = ioc.getBean(Yellow.class);
System.out.println("Yellow: "+bean5);
}
}
========================控制台打印结果==============================
Yellow: com.example.springbootdemo.boot.bean.Yellow@2c779e5
使用Spring提供的FactoryBean(工厂Bean)
=====================================================创建Color类=================================
package com.example.springbootdemo.boot.bean;
public class Color {
}
```
============================创建MyFactoryBean实现FactoryBean============
//创建一个Spring定义的FactoryBean(工厂Bean)
public class MyFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
System.out.println("MyFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
//是单实例?
//ture:这个bean是单实例,在容器中保存一份
//false : 多实例,每次获取都会创建一个新的bean
@Override
public boolean isSingleton() {
return true;
}
}
=====================================把myFactoryBean键入容器中==============================
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置类
public class MyConfig {
@Bean
public MyFactoryBean myFactoryBean(){
return new MyFactoryBean();
}
}
================================================测试======================================
/**
* 主程序类;主配置类
*
* @SpringBootApplication:这是一个SpringBoot应用
*
*/
@SpringBootApplication()
public class SpringBootDemoApplication {
public static void main(String[] args) {
//1.返回我们的IOC容器
ConfigurableApplicationContext ioc= SpringApplication.run(SpringBootDemoApplication.class, args);
//使用Spring提供的FactoryBean(工厂Bean) 获取的是用getObject创建的对象
//默认获取到的是工厂bean调用getObject创建的对象
Object bean6 = ioc.getBean("myFactoryBean");
System.out.println("myFactoryBean的类型:"+bean6.getClass());
/*是单实例?
ture:这个bean是单实例,在容器中保存一份
false : 多实例,每次获取都会创建一个新的bean
@Override
public boolean isSingleton() {
return true;
}*/
//true:单实例,
Object bean7 = ioc.getBean("myFactoryBean");
System.out.println(bean6==bean7);
//要获取工厂Bean本身,我们需要给id前面加一个&
Object bean8 = ioc.getBean("&myFactoryBean");
System.out.println("获取本身类型:"+bean8.getClass());
}
========================true 单实例输出结果=========================
MyFactoryBean...getObject...
myFactoryBean的类型:class com.example.springbootdemo.boot.bean.Color
true
=======================false 多是列输出结果=========================
MyFactoryBean...getObject...
myFactoryBean的类型:class com.example.springbootdemo.boot.bean.Color
MyFactoryBean...getObject...
false
=======================要获取工厂Bean本身,控制台输出================
获取本身类型:class com.example.springbootdemo.boot.config.MyFactoryBean
-
@Conditional
2.2、原生配置文件引入
2021年07月24日 加入 -
@ImportResource
引入xml配置文件到容器中:@ImportResource(“classpath:beans.xml”)
beans.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="haha" class="com.example.springbootdemo.boot.bean.User"> <property name="name" value="张三"></property> <property name="age" value="18"></property> </bean> <bean id="hehe" class="com.example.springbootdemo.boot.bean.Pet"> <property name="name" value="tomcat"></property> </bean> </beans>
导入方式:找个配置文件类,加上**@ImportResource(“classpath:beans.xml”)**
/* * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实列的 * 2、配置类本省也是组件 * 3 、proxyBeanMethods:代理bean的方法 * Full(proxyBeanMethods = true) 【保存每个@Bean方法被调用多少次返回的组件都是单实例的】 * Lite(proxyBeanMethods = false) 【每个@Bean方法被调用多少次返回的组件都是新创建的】 * 组件依赖必须使用Full模式默认,其他默认是Lite模式 * 最佳实战: * 1、配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断。 * 2、配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式。 * 4、@Import({User.class, DBHelper.class}) * 给容器中自动创建这两个类型的组件,默认组件的名字就是全类名:com.example.springbootdemo.boot.bean.User * * * 5、@ImportResource("classpath:beans.xml") 导入spring的配置文件 * * */ @Import({User.class, DBHelper.class,MyImportSelector.class,MyImportDefinitionRegistrar.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置类 @ImportResource("classpath:beans.xml") public class MyConfig { @Bean public MyFactoryBean myFactoryBean(){ return new MyFactoryBean(); } /** * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象 * @return */ @Bean//给容器中添加组件,以方法名作为组件的ID。返回类型就是组件类型。返回值,就是组件在容器中的实列。 public User user01(){ User zhansan = new User("张三",18); //user组件依赖了Pet组件 :proxyBeanMethods = true 就不会报错 zhansan.setPet(tomcatPet()); return zhansan; } @Bean("tom")//重命名组件名为tom public Pet tomcatPet(){ return new Pet("tomcat"); } }
测试容器是否存在:haha、hehe
/** * 主程序类;主配置类 * * @SpringBootApplication:这是一个SpringBoot应用 * */ @SpringBootApplication() public class SpringBootDemoApplication { public static void main(String[] args) { //1.返回我们的IOC容器 ConfigurableApplicationContext ioc= SpringApplication.run(SpringBootDemoApplication.class, args); boolean haha = ioc.containsBean("haha"); boolean hehe = ioc.containsBean("hehe"); System.out.println("haha:"+haha); System.out.println("hehe:"+hehe); } } ==============================测试结果=========================================== 1、没有导入spring配置文件时 haha:false hehe:false 2、导入spring配置文件时 haha:true hehe:true
2.3、配置绑定
创建Car类:
public class Car {
private String brand;
private Integer price;
}
1、@ConfigurationProperties(prefix = “mycar”)
2、@EnableConfigurationProperties + @ConfigurationProperties
注意点:一定要在配置类里面
应用场景:引用第三方类中没有@Component 时,可使用这个。
两个功能:
-
开启Car属性配置绑定功能
-
把这个Car这个组件自动注册到容器中
Car类上加注解:@ConfigurationProperties(prefix = “mycar”)
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
}
配置类中加注解:@EnableConfigurationProperties
//告诉SpringBoot这是一个配置类 == 配置类
@Configuration(proxyBeanMethods = true)
@EnableConfigurationProperties(Car.class)
//1、开启Car属性配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}
Controller 前段访问:
@RestController
public class HelloController {
@Autowired
Car car;
@RequestMapping("/car")
public Car car() {
return car;
}
}
访问:localhost:8080/car 显示结果:
{"brand":"BYD","price":100000}
3、@Component + @ConfigurationProperties
Car类添加注解:@Component + @ConfigurationProperties
/**
* 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
* @Component :放入容器中
* */
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
}
配置文件中的内容:
mycar.brand=BYD
mycar.price=100000
Controller 前段访问:
@RestController
public class HelloController {
@Autowired
Car car;
@RequestMapping("/car")
public Car car() {
return car;
}
}
访问:localhost:8080/car 显示结果:
{"brand":"BYD","price":100000}