SpringBoot2基础笔记
SpringBoot2基础笔记
一、HelloWorld
1. 创建Springboot工程
选择初始依赖,第一次使用,选择Web开发就可以了
2. 编写HelloWorld代码
3. 启动主程序
测试完成!Springboot太快了,爱了爱了!
二、SpringBoot特点
1. 依赖管理
- 父项目做依赖管理
<!-- 父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 上面的父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.1</version>
</parent>
<!-- 几乎管理了所有开发中常用的依赖版本 -->
- 开发导入starter场景启动器
- starter就是一组依赖,一个starter代表一个场景
- 所有场景启动器最底层的依赖就是 org.springframework.boot
- 无需关注版本号,自动版本仲裁
- 可以修改版本号
2. 自动配置
- 自动配置好Tomcat
- 引入web开发场景的时候就把Tomcat依赖引入了
- 自动配置好SpringMVC
- 引入web开发场景的时候就把SpringMVC依赖引入了
- 自动配置好Web场景功能,如:字符编码
- springboot配置好了所有web开发的常见场景,如dispatcherServlet
- 默认的包结构
- 也可以手动指定
@SpringBootApplication(scanBasePackages = "com.lxs")
- 也可以手动指定
- 各种配置拥有默认值
- 默认配置最终都是映射到某一个类上
- 配置文件(application.properties)的值最终会绑定到某个类上,这个类最终会在容器中创建对象
- 按需加载所有自动配置项
- 引入了哪些场景,这个场景的自动配置才能开启
- springboot所有的自动配置功能都在spring-boot-autoconfigure包里面
- ……
三、注解代替Spring配置文件完成IOC功能
1. 组件添加
以前是在xml配置文件里面配置bean标签来添加组件
2. @Configuration(相当于之前的xml配置文件)
- Full模式与Lite模式
- 最佳实战
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
- 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
- 最佳实战
/**
* 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2、配置类本身也是组件
* 3、proxyBeanMethods:代理bean的方法
* Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
* Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
* 组件依赖必须使用Full模式默认。其他默认是否Lite模式
*
*
*
*/
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
/**
* Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
* @return
*/
@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");
}
}
################################@Configuration测试代码如下########################################
@SpringBootApplication
public class MainApplication {
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);
}
//3、从容器中获取组件
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("组件:"+(tom01 == tom02));
//4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
//保持组件单实例
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:"+(user01.getPet() == tom));
}
}
3. @Bean、@Component、@Controller、@Service、@Repository
和之前的使用方式一样,给类上面加上注解,就能把组件添加到容器中
4. @ComponentScan、@Import
/**
* @Import({User.class, DBHelper.class})
* 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
*/
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}
5. @Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
这是他的子注解,每个不同的注解都表示不同的条件
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
/**
* Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
* @return
*/
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
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);
//2、查看容器里面的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
boolean tom = run.containsBean("tom");
System.out.println("容器中Tom组件:"+tom);
boolean user01 = run.containsBean("user01");
System.out.println("容器中user01组件:"+user01);
boolean tom22 = run.containsBean("tom22");
System.out.println("容器中tom22组件:"+tom22);
}
6. 原生配置文件引入
springboot也可以用之前配置文件的方法注入组件
@ImportResource
======================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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="haha" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.atguigu.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
@ImportResource("classpath:beans.xml")
public class MyConfig {}
======================测试=================
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
7. 配置绑定
读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用;
/**
1. 先把这个类添加到容器中,只有在容器中的组件,才会拥有SpringBoot提供的强大功能
*/
@Component
@ConfigurationProperties(prefix = "mycar") //prefix代表在properties文件中的前缀
public class Car {
private String brand;
private Integer price;
properties文件内容
mycar.brand=BYD
mycar.price=999
@EnableConfigurationProperties
这也是一个配置绑定的注解,只不过这个是写在配置类上的(Car类中不需要写@Component注解了。。。)
- 开启指定的类的属性配置绑定功能
- 把这个类加入到组件中
@Configuration
@EnableConfigurationProperties(Car.class)
public class MyConfig{
}
四、自动配置原理
先从主程序类的@SpringBootApplication来讲
点进去后,发现这是一个组合注解,下面有三个其他注解
1. @SpringBootConfiguration
里面是个Configuration注解,@Configuration。代表当前是一个配置类
2. @ComponentScan
指定扫描哪些,Spring注解;
3. @EnableAutoConfiguration
其他两个注解都不是自动配置相关的,我门点这个注解进去,发现它任然是一个组合注解
3-1. @AutoConfigurationPackage
自动配置包,指定了默认的包规则
点进去:
@Import(AutoConfigurationPackages.Registrar.class)//给容器导入一个组件
public @interface AutoConfigurationPackage {
}
原理:利用Registrar给容器中批量注册组件,将指定一个包下的所有组件导入进来,这个注解标注在哪个类上就是那个类的所在包下。标注在主程序上,所以是主程序类所在包
3-2. @Import(AutoConfigurationImportSelector.class)
也是要批量导入组件
- 利用
getAutoConfigurationEntry(annotationMetadata);
给容器中批量导入一些组件 - 调用
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)
获取到所有需要导入到 容器中的配置 - 利用工厂加载
Map<String, List<String>> 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-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
# 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,\
……127个自动配置类
4. 按需开启自动配置项
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。
必须要满足条件,可以去配置类中查看源码,作用就是导入需要的starter才能使对应的自动配置生效
4-1. 修改视图解析器的默认名称
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
给容器中加入了文件上传解析器;
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
}
5. 总结
- SpringBoot先加载所有的自动配置类,xxxAutoConfiguration
- 每个自动配置类按照条件进行生效
- 生效的配置类就会给容器中装配很多的组件
- 只要容器中有这些组件,相当于这些功能就有了
- 只要用户有自己的配置的,就以用户的优先
- 每个配置类一生效就会绑定配置文件中的值
5-1. 定制化配置
- 用户自己使用@Bean替换底层自动配置的组件
- 在配置文件中修改属性(常用)
xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties
6. 最佳实践
- 引入场景依赖
- 查看自动配置了哪些(选做)
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
- 是否需要修改
- 参照文档修改配置项
- 自定义加入或者替换组件
- @Bean、@Component。。。
- 自定义器 XXXXXCustomizer;
- ……
五、开发技巧
1. Lombok
简化JavaBean开发
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
idea中搜索安装lombok插件
===============================简化JavaBean开发===================================
@NoArgsConstructor //无参构造器
//@AllArgsConstructor 有参构造器
@Data //get,set方法
@ToString //ToString方法
@EqualsAndHashCode //重写equals和hashcode 方法
public class User {
private String name;
private Integer age;
private Pet pet;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
================================简化日志开发===================================
@Slf4j //注入日志类
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(@RequestParam("name") String name){
log.info("请求进来了....");
return "Hello, Spring Boot 2!"+"你好:"+name;
}
}
2. dev-tools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
项目或者页面修改以后:Ctrl+F9;
六、配置文件
1. properties
同以前的properties用法
2. yaml
2-1. 基本语法
- key: value;kv之间有空格
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注释
- 字符串无需加引号,如果要加,''与""表示字符串内容 会被 转义/不转义
2-2. 数据类型
- 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
- 对象:键值对的集合。map、hash、set、object
行内写法: k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
- 数组:一组按次序排列的值。array、list、queue
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
2-3. 示例
@Data
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
@Data
public class Pet {
private String name;
private Double weight;
}
# yaml表示以上对象
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
3. 配置提示
自定义的类和配置文件绑定一般没有提示。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 这个插件的功能是打包的时候把这个配置提示得到类去掉 -->
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>