SpringBoot2 基础篇 1
转载:https://blog.csdn.net/u011863024/article/details/113667634
SpringBoot 简介
SpringBoot 文档
官方文档:
https://spring.io/projects/spring-boot
https://docs.spring.io/spring-boot/docs/2.3.7.RELEASE/reference/html/index.html
为什么用SpringBoot
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”.link
能快速创建出生产级别的Spring应用。
SpringBoot优点
Create stand-alone Spring applications
创建独立Spring应用
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
内嵌web服务器
Provide opinionated ‘starter’ dependencies to simplify your build configuration
自动starter依赖,简化构建配置
Automatically configure Spring and 3rd party libraries whenever possible
自动配置Spring以及第三方功能
Provide production-ready features such as metrics, health checks, and externalized configuration
提供生产级别的监控、健康检查及外部化配置
Absolutely no code generation and no requirement for XML configuration
无代码生成、无需编写XML
SpringBoot是整合Spring技术栈的一站式框架
SpringBoot是简化Spring技术栈的快速开发脚手架
SpringBoot缺点
人称版本帝,迭代快,需要时刻关注变化
封装太深,内部原理复杂,不容易精通
基础入门 SpringBoot
开发环境介绍
Java 8
Maven 3.3+
IntelliJ IDEA 2019
Maven配置(若没有配置Maven镜像加速,建议配置镜像加速)
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
1. 基础入门-SpringBoot-Hello World 项目
1. 创建 maven 工程,hello-word-project
2. 引入依赖 pom.xml 文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
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. 编写 controller
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!
注:若SpringBoot工程没有配置 server.port 端口设置,那么默认的端口为8080
6. 设置配置
maven 工程的 resource 文件夹中创建 application.yml 或者 application.properties 文件
# 设置端口号
server.port=8082
7. 打包部署
在 pom.xml 添加
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
在IDEA的Maven插件上点击运行 clean 、package,把 helloworld 工程项目的打包成jar包,
打包好的jar包被生成在helloworld工程项目的target文件夹内。
用cmd运行java -jar boot-01-helloworld-1.0-SNAPSHOT.jar,既可以运行helloworld工程项目。
将jar包直接在目标服务器执行即可。
2. 基础入门-SpringBoot-依赖管理特性
父项目做依赖管理
<--依赖管理-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<--上面项目的父项目如下:-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<--它几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制-->
开发导入starter场景启动器
见到很多 spring-boot-starter-* : *就某种场景
只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
更多SpringBoot所有支持的场景
见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
<--所有场景启动器最底层的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
无需关注版本号,自动版本仲裁
引入依赖默认都可以不写版本
引入非版本仲裁的jar,要写版本号。
可以修改默认版本号
查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
在当前项目里面重写配置,如下面的代码。
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
IDEA快捷键:
ctrl + shift + alt + U:以图的方式显示项目中依赖之间的关系。
alt + ins:相当于Eclipse的 Ctrl + N,创建新类,新包等。
3. 基础入门-SpringBoot-自动配置特性
自动配好Tomcat
引入Tomcat依赖
配置Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
自动配好SpringMVC
引入SpringMVC全套组件
自动配好SpringMVC常用组件(功能)
自动配好Web常见功能,如:字符编码问题
SpringBoot帮我们配置好了所有web开发的常见场景
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);
}
}
默认的包结构
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
无需以前的包扫描配置
想要改变扫描路径
@SpringBootApplication(scanBasePackages="com.sevattal")
@ComponentScan 指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.sevattal")
各种配置拥有默认值
默认配置最终都是映射到某个类上,如:MultipartProperties
配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
非常多的starter
引入了哪些场景这个场景的自动配置才会开启
SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
4. 底层注解-@Configuration详解
基本使用
public class Pet {
private String name;
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class User {
private String name;
private int age;
private Pet pet;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
}
/**
* 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
* 2、配置类本身也是组件
* 3、proxyBeanMethods:代理bean的方法
* Full(proxyBeanMethods = true)(保证每个@Bean方法被调用多少次返回的组件都是单实例的)(默认)
* Lite(proxyBeanMethods = false)(每个@Bean方法被调用多少次返回的组件都是新创建的)
*/
@Configuration(proxyBeanMethods = true) //告诉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测试代码如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.sevattal")
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.sevattal.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));
}
}
最佳实战
配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)
IDEA快捷键:
Alt + Ins: 生成 getter,setter、构造器等代码。
Ctrl + Alt + B: 查看类的具体实现代码。
5. 底层注解-@Import导入组件
@Bean、@Component、@Controller、@Service、@Repository,它们是Spring的基本标签,在Spring Boot中并未改变它们原来的功能。
@ComponentScan 在基础入门-SpringBoot-自动配置特性有用例。
@Import({User.class, DBHelper.class})给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}
测试类:
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//...
//5、获取组件
String[] beanNamesForType = run.getBeanNamesForType(User.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
DBHelper bean1 = run.getBean(DBHelper.class);
System.out.println(bean1);
6. 底层注解-@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);
//2、查看容器里面的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
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
}
7. 底层注解-@ImportResource导入Spring配置文件
比如,公司使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource粉墨登场。
bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...">
<bean id="haha" class="com.sevattal.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.sevattal.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
使用方法:
@ImportResource("classpath:beans.xml")
public class MyConfig {
...
}
测试类:
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
}
8. 底层注解-@ConfigurationProperties配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用
传统方法:
public class getProperties {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties pps = new Properties();
pps.load(new FileInputStream("a.properties"));
Enumeration enum1 = pps.propertyNames();//得到配置文件的名字
while(enum1.hasMoreElements()) {
String strKey = (String) enum1.nextElement();
String strValue = pps.getProperty(strKey);
System.out.println(strKey + "=" + strValue);
//封装到JavaBean。
}
}
}
Spring Boot一种配置配置绑定:
@ConfigurationProperties + @Component
假设有配置文件application.properties
mycar.brand=BYD
mycar.price=100000
只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
Spring Boot另一种配置配置绑定:
@EnableConfigurationProperties + @ConfigurationProperties
开启Car配置绑定功能
把这个Car这个组件自动注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}
9. 自动配置【源码分析】-自动包规则原理
Spring Boot应用的启动类:
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
分析下@SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
重点分析@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。
@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@Configuration代表当前是一个配置类。
@ComponentScan
指定扫描哪些Spring注解。
@ComponentScan 在07、基础入门-SpringBoot-自动配置特性有用例。
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
重点分析@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class)。
@AutoConfigurationPackage
标签名直译为:自动配置包,指定了默认的包规则。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)//给容器中导入一个组件
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
- 利用Registrar给容器中导入一系列组件
- 将指定的一个包下的所有组件导入进MainApplication所在包下。
10. 自动配置【源码分析】-初始加载自动配置类
@Import(AutoConfigurationImportSelector.class)
1. 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2. 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3. 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4. 从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
# 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
# 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,\
...
虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是xxxxAutoConfiguration按照条件装配规则(@Conditional),最终会按需配置。
如AopAutoConfiguration类:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = "auto",
havingValue = "true",
matchIfMissing = true
)
public class AopAutoConfiguration {
public AopAutoConfiguration() {
}
...
}
11. 自动配置【源码分析】-自动配置流程
以DispatcherServletAutoConfiguration的内部类DispatcherServletConfiguration为例子:
@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默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先。
总结:
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。(xxxxProperties里面读取,xxxProperties和配置文件进行了绑定)
生效的配置类就会给容器中装配很多组件
只要容器中有这些组件,相当于这些功能就有了
定制化配置
用户直接自己@Bean替换底层的组件
用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —-> application.properties
12. 最佳实践-SpringBoot应用如何编写
1. 引入场景依赖
官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
2. 查看自动配置了哪些(选做)
自己分析,引入场景对应的自动配置一般都生效了
配置文件中debug=true开启自动配置报告。
Negative(不生效)
Positive(生效)
3. 是否需要修改
参照文档修改配置项
官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
自己分析。xxxxProperties绑定了配置文件的哪些。
自定义加入或者替换组件
@Bean、@Component…
自定义器 XXXXXCustomizer;
…
13. 最佳实践-Lombok简化开发
Lombok用标签方式代替构造器、getter/setter、toString()等鸡肋代码。
spring boot已经管理Lombok。引入依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
IDEA 中 File->Settings->Plugins,搜索安装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;
}
}
简化日志开发
@Slf4j
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(@RequestParam("name") String name){
log.info("请求进来了....");
return "Hello, Spring Boot 2!"+"你好:"+name;
}
}
14. 最佳实践-dev-tools (热更新)
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
快捷键: ctrl + shift + alt + / 选择registy
在IDEA中,项目或者页面修改以后:Ctrl+F9。
15. 最佳实践-Spring Initailizr(创建SpringBoot项目)
Spring Initailizr官网:https://start.spring.io/
Spring Initailizr是创建Spring Boot工程向导。
在IDEA中,菜单栏New -> Project -> Spring Initailizr。