目录
入门
Hello World
一、系统要求
- Java 8 & 兼容java14 .
- Maven 3.3+
- idea 2019.1.2
二、需求:浏览发送/hello
请求,响应Hello,Spring Boot 2
- 创建maven工程
- 在
POM.xml
中添加以下依赖:
<!-- 要使用springboot就要引入spring-boot-starter-parent -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<!--开发web应用需要导入下面这个依赖spring-boot-starter-web-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 创建主程序:新建文件
src/main/java/com/atguigu/boot/MainApplication.java
,在其中写代码:
/**
* 1. 给该类标注注解:@SpringBootApplication
* @SpringBootApplication相当于告诉这是一个SpringBoot应用
* 加了@SpringBootApplication的类称为主程序类,相当于是所有程序的启动入口
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);// 固定写法
}
}
- 编写业务:新建文件
src/main/java/com/atguigu/WorldController.java
并在其编写代码:
// @RequestBody// 4. 因为这个类会有很多方法都是返回字符串,那么就需要给每个方法都加这句注释,太冗余,我们可以直接将该注释加在类上,表明这个类的每一个方法的返回值是直接写给浏览器的,不是跳转到某页面
// @Controller// 1. 表明这个类是个控制器,专门用来处理前端的请求
@RestController// 5. 这个注释是@RequestBody和@Controller的合体,所以直接写他
public class HelloController {
@RequestBody// 3. 因为返回的是字符串,所以要加这个注释
@RequestMapping("/hello")// 2. 映射请求,当请求后缀是/hello时,给他返回一句话:"Hello, Spring Boot 2!"
public String handle01(){
return "Hello, Spring Boot 2!";
}
}
- 运行程序:直接运行main方法,项目启动后在浏览器输入
http://localhost:8080/hello
,将会输出Hello, Spring Boot 2!
。
配置
新建springboot的配置文件src/main/resources/application.properties
,在这里面可以修改tomcat、springMVC的配置等等,来体验一下,在里面写代码修改端口号:server.port=8888
,以后运行main方法,项目启动后在浏览器输入http://localhost:8888/hello
,才会输出Hello, Spring Boot 2!
。
在官网的application-properties中可以查看具体可以进行哪些配置
部署
将项目打成jar包,jar包中包含项目运行环境,能直接运行项目。在POM.xml
文件中添加以下依赖:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
按以下步骤进行打包(多写了一个1)
打包成功后会出现下面的jar包
在cmd中运行以下jar包:
如果项目启动不成功,那么在cmd的属性中取消选中“快速编辑模式”
如果系统不下载你添加的依赖,刷新一下:
springboot特点
依赖管理
一、每一个springboot项目都会有一个父项目spring-boot-starter-parent
:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
父项目一般用来做依赖管理,父项目中会声明很多依赖,子项目继承父项目,以后子项目写依赖就不需要版本号了。spring-boot-starter-parent
的父项目是:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
几乎声明了所有开发中常用的依赖的版本号,这样,以后我们写依赖的时候就不用写版本号了,这被称为自动版本仲裁机制。但是如果我们想用某个特定的版本,这个特定的版本不是常用的依赖的版本,我们可以自定义:
- 查看
spring-boot-dependencies
里面规定当前依赖的版本 用的 key。 - 在当前项目里面重写配置:
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
如果我们引入非版本仲裁的jar,即我们引入的jar包不在spring-boot-dependencies中,则要写版本号。
二、关于导入的starter场景启动器
- 我们导入的
spring-boot-starter-*
:*
就某种场景,就是starter场景启动器 - 只要引入
spring-boot-starter-*
,这个场景的所有常规需要的依赖我们都自动引入 - SpringBoot所有支持的场景
- 见到的
*-spring-boot-starter
: 第三方为我们提供的简化开发的场景启动器。 - 所有场景启动器最底层的依赖都是springboot自动配置的核心依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
自动配置
springboot帮我们自动配好了很多东西:
底层注解
@Configuration
创建一个类src/main/java/com/atguigu/boot/config/MyConfig.java
,并为其添加注解:@Configuration
,用以告诉SpringBoot这是一个配置类,这也就是一个配置文件。
在这个类中写代码来构造往容器中添加的组件(类中肯定只能写方法来构造组件),并为方法添加@Bean
注解:
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
return new User("zhangsan", 18);
}
如果你不想用方法名作为组件名,给@Bean
中传递一个字符串,就会以字符串的内容作为组件名:
@Bean("tom22")
public Pet tomcatPet(){
return new Pet("tomcat");
}
这样我们就往容器中注册了两个组件,这两个组件默认是单实例的,我们无论从容器中获取组件多少次结果都是一样的,在MainApplication.java
中写代码测试:
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("组件:"+(tom01 == tom02));// true
}
}
使用@Configuration
标注的类也是一个组件,因为在容器中,配置类也是容器中的一个组件,在MainApplication.java
中写代码测试:
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);// com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892,代理对象
}
}
proxyBeanMethods属性
springboot2比1多了一个proxyBeanMethods
属性,且默认值为true
,这就使得外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象,在MainApplication.java
中写代码测试::
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);// com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892,代理对象
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
//保持组件单实例
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);// true
}
}
这是因为每一次调用时SpringBoot总会检查这个组件是否在容器中有,如果有则直接拿来用,如果没有则调用方法,如此来保持组件单实例。如果将proxyBeanMethods
设为false
,每次调用方法都会重新创建组件:
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);// com.atguigu.boot.config.MyConfig@304a9d7b
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);// false
}
}
这也就引出了@Configuration
的两个配置:
- Full:全配置,即
proxyBeanMethods = true
,保证每个@Bean
方法被调用多少次返回的组件都是单实例的 - Lite:轻量级配置,即
proxyBeanMethods = false
,每个@Bean
方法被调用多少次返回的组件都是新创建的,每次调用他就不会去检查容器中是否有这个组件,运行速度更快。
组件依赖必须使用Full模式默认。其他默认是否Lite模式
这主要解决了组件依赖问题,举例:现在有一个Pet类,Pet.java
代码如下:
@ToString
@Data
@NoArgsConstructor //无参构造器
@AllArgsConstructor //全参构造器
public class Pet {
private String name;
}
还有一个User类,User.java
代码如下:
@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;
}
}
让User组件依赖Pet组件,MyConfig.java
代码如下:
@Configuration(proxyBeanMethods = true);
public class MyConfig {
@Bean
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");
}
}
若proxyBeanMethods = true
,那么User组件使用的Pet和Pet组件创建的是同一个,因为每次运行方法的时候他都拿的是容器中现有的组件,在MainApplication.java
中测试:
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:"+(user01.getPet() == tom));// ture
}
}
若proxyBeanMethods = false
,则上述测试代码返回false,因为每次调用方法都重新创建一个对象。
综上,配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断;配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
@Bean、@Component、@Controller、@Service、@Repository
给容器中注册组件,用以前的办法也可以。在类上标注@Component代表他是一个组件,标注@Controller代表他是一个控制器,标注@Service代表他是一个业务逻辑组件,标注@Repository代表他是一个数据库层组件,只要这些组件写在默认包扫描范围内,即MainApplication.java
所在类,除了主配置类能写配置外,也可以使用Configuration
自定义一些配置类
@ComponentScan、@Import
@ComponentScan:通过包扫描指定包扫描规则
@Import:给容器中添加组件的另一个方法,给容器中导入一个组件,可以把它写在任何一个配置类或者组件中都行,写在容器中的组件的类上,你这个类可以是配置类或者其他Controller,他接受一个数组,数组中存放指定类型的组件。
MyConfig.java
代码如下:
@Import({User.class, DBHelper.class});// 导入两个组件
@Configuration(proxyBeanMethods = true);
public class MyConfig {
@Bean
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");
}
}
在MainApplication.java
中测试是否导入成功:
@ComponentScan("com.atguigu.boot")
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//5、获取组件
// 我们导入了好几个User组件,所以遍历查找所有的User组件
String[] beanNamesForType = run.getBeanNamesForType(User.class);
System.out.println("======");
for (String s : beanNamesForType) {
System.out.println(s);
// com.atguigu.boot.bean.User
// user01
}
// 获取DBHelper组件,看是否导入成功
DBHelper bean1 = run.getBean(DBHelper.class);
System.out.println(bean1);// ch.qos.logback.core.db.DBHelper@2aa27288
}
}
@Conditional
@Conditional:条件装配,即满足Conditional指定的条件,则进行组件注入,才给容器中注入相应的组件。他是一个跟注解,她下面派生了很多注解
当容器中存在指定bean,即存在指定组件时,才执行某些事
当容器中不存在指定bean,即存在指定组件时,才执行某些事
当容器中有指定类时,才执行某些事
当容器中没有指定类时,才给容器中注入某些组件
当项目的类路径中存在某资源时,才执行某些事
当是指定的Java版本号时,才执行某些事
当应用是个web应用时,才执行某些事
当应用不是个web应用时,才执行某些事
当容器中指定的组件只有一个实例,或者他有很多个实例但只有一个主实例时,才执行某些事
当配置文件配置了某些属性时,才执行某些事
需求:user01组件依赖tom组件,正常情况下,就算容器中没有tom组件,也会注册user01组件,MyConfig.java
代码如下,不注册tom组件:
@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");
}
}
在MainApplication.java
中测试是否注册user01组件、tom组件:
@SpringBootApplication
public class MainApplication {
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
}
}
但我们现在希望如果容器中没有tom组件,那也别注册user01组件了,那我们可以在user01组件上添加注解@ConditionalOnBean(name = "tom")
,表示只有存在tom组件才注册user01组件,MyConfig.java
代码如下:
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
@Bean
@ConditionalOnBean(name = "tom")
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");
}
}
也可以把@ConditionalOnMissingBean(name = "tom")
标注在类上面,如果标注在类上面,表明容器中有tom组件,类中的所有配置才生效,MyConfig.java
代码如下:
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
@ConditionalOnBean(name = "tom")
public class MyConfig {
@Bean
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");
}
}
以上两种代码在MainApplication.java
中测试发现都没有注册user01组件、tom组件:
@SpringBootApplication
public class MainApplication {
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);// false
}
}
需求:没有tom组件时,类中的所有配置才生效。使用@ConditionalOnMissingBean
:
@ConditionalOnMissingBean(name = "tom")
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
@Bean
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");
}
}
在MainApplication.java
中测试发现都注册了user01组件、tom22组件:
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
boolean tom22 = run.containsBean("tom22");
System.out.println("容器中tom22组件:"+tom22);// true
boolean user01 = run.containsBean("user01");
System.out.println("容器中user01组件:"+user01);// false
}
}
原生配置文件引入:@ImportResource
以前可能在springboot的配置文件中写很多的组件导入,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>
很多人可能还在使用上面这种配置方式,或者我们引入的第三方包比较老,他就是以上面这种方式配置的,这种配置方式在注解配置中是不生效的,在MainApplication.java
中测试容器中是否有haha,hehe两个组件:
@SpringBootApplication
public class MainApplication {
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);// false
System.out.println("hehe:"+hehe);// false
}
}
现在我们想把上面这种配置方式迁移成注解配置的方式,那么可以随便在某个配置类上使用@ImportResource("classpath:资源路径")
(这行代码只用写一次),会自动将该资源路径下的配置文件重新解析放在容器中,MyConfig.java
代码如下:
@ImportResource("classpath:beans.xml")
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
@Bean
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");
}
}
配置绑定
我们习惯将经常变化的东西配置到配置文件中,比如将数据库的链接地址、账号密码配置到配置文件properties中,未来创建数据库连接池时,会解析配置文件,解析到数据库连接池JavaBean中。如果你在properties中写了很多配置,创建数据库连接池时还需要使用正则表达式查找与数据库相关的配置,太麻烦了,在springboot中,可以使用@ConfigurationProperties
来完成,非常方便快捷。
现在我们有一个Car类,Car.java中代码如下:
public class Car {
private String brand;
private Integer price;
// 省略了getter、setter、toString
}
我们现在将与Car类有关的配置放在配置文件中,springboot核心配置文件application.properties
代码如下:
mycar.brand=YD
mycar.price=100000
注意:这些配置文件只能写在
application.properties
中!因为只有他才是springboot的核心配置文件
@Component + @ConfigurationProperties
现在使用注解@ConfigurationProperties(prefix = "类中的属性和配置文件那个前缀下的属性一一绑定")
读取配置文件。为了让@ConfigurationProperties
生效,需要把这个组件(使用@ConfigurationProperties
定义的类)加到容器中,因为只有容器中的组件才拥有springboot提供的功能,使用注解@Component
,Car.java
中代码如下:
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
// 省略了getter、setter、toString
}
测试一下,src/main/java/com/atguigu/boot/controller/HelloController.java
代码如下:
public class HelloController {
@Autowired// 使用spring的自动注入,将容器中的car直接拿过来
Car car;
@RequestMapping("/car")
public Car car(){
return car;
}
}
项目启动后在浏览器输入:http://localhost:8888/car
,展示
@EnableConfigurationProperties + @ConfigurationProperties
另一种解决方法,在配置类MyConfig.java
中配置@EnableConfigurationProperties
注解(因为配置类在容器中,他是容器中的组件,所以一定要在配置类中写),开启属性配置功能,开启谁的属性配置功能?因为Car类想跟别人绑定,所以是开启Car的,将其作为参数传递进去。@EnableConfigurationProperties
有两个功能:
- 开启Car配置绑定功能
- 把这个Car这个组件自动注册到容器中
MyConfig.java
中代码如下:
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
@EnableConfigurationProperties(Car.class)// 开启属性配置功能
public class MyConfig {
@Bean
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");
}
}
写了@EnableConfigurationProperties
就不用在Car.java
中写@Component
,Car.java
中代码如下:
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
// 省略了getter、setter、toString
}
有些时候,Car类可能来源于第三方包,我们是引用的别人的类,人家在这个类中没有写@Component
,那么就可以使用这种方法
自动配置【源码分析】
@SpringBootApplication
这个注解相当于下面三个注解:@SpringBootConfiguration
、@EnableAutoConfiguration
、@ComponentScan("com.atguigu.boot")
。@SpringBootApplication
的核心也就包含在这三个注解中。@SpringBootApplication
源码:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
======================
@SpringBootConfiguration
里面就一个@Configuration
,代表当前是一个配置类
@ComponentScan
指定扫描哪些,他有两个默认的扫描器TypeExcludeFilter.class
、AutoConfigurationExcludeFilter.class
,详见【Spring注解视频】
@EnableAutoConfiguration
他也是一个合成注解,除了源注解外,其他注解有:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
@AutoConfigurationPackage
自动配置包?指定了默认的包规则。查看源码发现:
@Import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件
public @interface AutoConfigurationPackage {}
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
其实就是使用@Import往容器中导入了AutoConfigurationPackages.Registrar
组件,AutoConfigurationPackages.Registrar
用于往容器中批量注册组件,它会将指定的一个包下(MainApplication
所在包下)的所有组件导入进来,这也就解释了为什么默认包路径时MainApplication
所在包
@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-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,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
虽然我们127个场景(xxxxAutoConfiguration
)的所有自动配置启动的时候默认全部加载。然而,springboot容器中没有这么多组件,这是因为springboot按照条件装配规则(@Conditional
)按需开启自动配置项,只有存在某个类,配置才生效,才把组件导入。
自动配置流程
源码解析:
@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() {}
总结:
- SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。默认会从
xxxxProperties
里面拿。xxxProperties
和配置文件进行了绑定 - 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
(1)用户直接自己@Bean替换底层的组件
(2)用户去看这个组件是获取的配置文件什么值就去修改。
流程:
xxxxxAutoConfiguration
—> 组件 —>xxxxProperties
里面拿值 ---->application.properties
最佳实践
springboot应用如何编写
一、引入场景依赖:参考资料
二、查看自动配置了哪些(选做),有以下两种方法:
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中
debug=true
开启自动配置报告。Negative
(不生效)`Positive`(生效)
三、是否需要修改
- 参照文档修改配置项或者自己分析
xxxxProperties
绑定了配置文件的哪些。 - 自定义加入或者替换组件:
@Bean
、@Component
。。。 - 自定义器
XXXXXCustomizer;
Lombok简化开发
以前我们写JavaBean的时候要写JavaBean的getter、setter方法,有参、无参构造器,重写toString等等,Lombok可以用来简化这些。
- 在pom.xml中添加以下依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- idea中搜索安装lombok插件
- 以后在JavaBean中可以通过lombok的注解来简化开发,
Pet.java
中代码如下,只用写属性即可
@ToString// lombok的注解,会在编译这个类的时候帮我们生成toString,而不是在源代码中生成
@Data// lombok的注解,用于帮我们生成已有属性的getter、setter
@NoArgsConstructor// lombok的注解,用于帮我们生成无参构造器
@AllArgsConstructor// lombok的注解,用于帮我们生成全参构造器
// 除此之外,还有@EqualsAndHashCode,也是lombok的注解,用于帮我们重写Equals和HashCode,不过本代码用不上,这里只提一下
public class Pet {
private String name;
}
- lombok也可以简化日志开发,lombok有一个注解
@Slf4j
,用于注入日志类,以后我们再也不用在控制台System.out
了,我们想要记录东西都可以用日志,这个注解会自动往类中注入log
属性,他是日志记录器,HelloController.java
代码如下:
@Slf4j
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(@RequestParam("name") String name){
log.info("请求进来了....");
return "Hello, Spring Boot 2!"+"你好:"+name;
}
}
dev-tools
用于热更新,代码修改后不用重启项目就可以看到效果,项目或者页面修改以后按下Ctrl+F9
即可,在pom.xml中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
他其实也是一个restart,只是系统帮你自动重启项目了,你不用再手动点击按钮重启项目了,你如果想用重新加载,需要用JRebel,你变了哪些内容,他就只更改你变了的那些内容
Spring Initailizr(项目初始化向导)
我们之前开发springboot应用需要参考官方文档,现在在idea中新建项目时可以选择Spring Initailizr,
点击next,取好名字,
之后你需要什么在这里勾选就好了,
也可以选择springboot版本,选好了后点击next,然后点击finish,他就会联网自动帮我们把项目下载下来,他会帮我们把整个项目的目录结构创建好,
还会把所有依赖引入好,
并帮我们创建好主程序类,他创建的Boot01Helloworld2Application.java
的代码如下:
package com.atguigu.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Boot01Helloworld2Application {
public static void main(String[] args) {
SpringApplication.run(Boot01Helloworld2Application.class, args);
}
}
以后使用Spring Initailizr开发,我们只用关心业务逻辑,其他的他都自动创建好了