SpringBoot学习笔记

152 阅读7分钟

SpringBoot学习笔记

​ springboot是在spring的基础上的一款更加简便高效的开发框架,对很多技术都提供了默认的配置,实现了"just run"

springboot的特征:

  1. 创建独立的Spring程序
  2. 内嵌了Tomcat、Jetty、Undertow(无需部署成war)
  3. 启动器(starter)中包含了大量的依赖坐标,并且进行了版本的管理
  4. 提供了热部署工具
  5. 只需要少量的自定义配置去覆盖默认配置

springboot的启动器

​ springboot提供了启动器,启动器内包含了此启动器可能依赖的所有坐标,在创建一个springboot项目后,pom中会自动继承一个启动器的父工程,在父工程中,针对父工程的版本进行了大量的版本整合,所以我们不需要太过在意版本冲突问题。

例如

​ web启动器:spring-boot-starter-web

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

​ 点进启动器看会发现web启动器包含了以下的依赖

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.3.3.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>2.3.3.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>2.3.3.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.8.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.8.RELEASE</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

由此,springboot的特点3的优势就展现了出来,不需要我们记住太多的坐标,只需要导入一个启动器即可导入大量的依赖,并且这些依赖的版本都是spring为我们整理好的,不需要担心版本冲突的问题


springboot的热部署

​ springboot的热部署实现了我们在开发的过程中,不需要重启项目就能使我们对代码的改动生效,可以节约一些时间。

原理

​ springboot在启动的时候会创建两个ClassLoader,其中一个(Loader1)用来加载那些不会改变的静态资源,另一个(Loader2)用来加载那些容易改变的资源,当我们开启了自动编译之后,springboot会将其做比对,如果代码发生了变动,那么就会创建一个新的Loader2去替换之前的Loader2,从而实现热部署。

​ 但是如果发生变动的内容存在于/META-INF/maven, /META-INF/resources, /resources, /static, /public, or /templates这些目录下时,不会触发restert,而是触发live reload,这种live reload不会使项目重新编译,而是直接实现资源的替换。

热部署开启的方式

  • 首先引入开发者工具的依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
  • 然后在idea设置里打开自动编译项目(默认关闭)

alert

  • 最后按ctrl+alt+shift+/,然后点击注册,在注册中勾选如下的选项即可实现热部署

alert


springboot的自动配置

​ springboot为我们提供了大量的默认的配置,我们无需配置那些通用的内容,但是还是要了解boot的自动配置的原理。

springboot的自动配置原理

  1. 首先,springboot有一个启动类,这个启动类idea默认会放在我们域名下,并且以Application结尾

alert

我们来分析以下这个主启动类,这个主启动类看起来就是一个一般的java类,有一个main程序的入口,此外就是一个SpringBootApplication注解和这个SpringApplication的run方法。

先来看看这个SpringBootConfiguration注解

alert

在boot的源码中采取了SPI的思想,通过创建公共接口,实现实体类的热插拔。在boot的底层源码中遵循了一种规范,即如果在类路径下的META-INF下存在spring.factories文件,那么会被boot进行解析,解析之后通过反射的方式加载对应的实体类并存入IOC容器,此外,下图中的选择器会实现对spring.factories文件的筛选解析,没有引用指定实体类的自动配置类则会被过滤,实现一种基于接口的动态实现。

alert

springboot的自动配置类采用了Conditional*注解,实现热插拔

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)//这个注解表示当此类不存在时,这个配置类就不会被加载进容器(即此类失效)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

springboot的自定义配置

​ 有很多东西springboot不可能实现自动配置,或者有时候我们不需要一些自动配置,而是我们自定义一些配置,这个时候在yml文件里面到底写一些什么内容呢?

  • 方式1:查看自动配置依赖中的spring.factories文件

alert

​ 然后在文件中找到EnableAutoConfig下面的配置类,找到你自己想要自己配置的配置类点进去(比如说RedisAutoConfiguration)

​ 然后在这个配置类上面的EnableConfigurationProperties注解中找到对应的Properties,点进去就会看到我们可以自己配置的字段的名称

@ConfigurationProperties(prefix = "spring.redis")//这里使我们要在yml中输入的前缀名
public class RedisProperties {

   /**
    * Database index used by the connection factory.
    */
   private int database = 0;				//这些属性就是我们可以自定义的字段

   /**
    * Connection URL. Overrides host, port, and password. User is ignored. Example:
    * redis://user:password@example.com:6379
    */
   private String url;						//自己配置uil

   /**
    * Redis server host.
    */
   private String host = "localhost";		//自己配置ip地址等等

yml属性绑定

​ yml中可以配置各种数据类型,而且可以通过注解实现对实体类中属性的注入

ConfigurationProperties注解绑定

​ ConfigutationProperties注解主要用于多个属性的绑定,例如在一个类中的所有属性绑定

方式1:set方法注入

在yml文件中配置如下属性

# 这里采用了松散绑定,可以自动匹配大小写 - _
yml:
  test:
    name: 周杰伦
    age: 22
    son:
      name: 周杰
      age: 10

然后在需要注入属性的实体类中使用ConfigurationProperties注解

@Conmonent//这种方式一定要手动将这个加入IOC
@Data
@ConfigurationProperties("yml.test")//set方法注入属性,在配置类中前缀不支持驼峰,支持羊肉串模式a-b
@Validated//开启jsr303校验
public class TestYml {
    private String name;
    private Integer age;
    private Son son=new Son();//注意这里是属性注入,不是注入对象,所以这里要有对象实例才能实现注入属性

    @Data
    class Son{
        private String name;
        private Integer age;
    }
}

注意: 如果一个配置类只配置@ConfigurationProperties 注解,而没有使用@Component,那么在 IOC 容器中是获取不到 properties 配置文件转化的 bean。说白了 @EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了启用注入


方式2:构造函数注入

yml文件中的配置不变

要使用构造函数绑定,必须使用@EnableConfigurationProperties或配置属性扫描启用类。 不能对由常规 Spring 机制创建的 Bean 使用构造函数绑定(例如@Component Bean、通过 @Bean 方法创建的 Bean 或使用@Import 加载的 Bean)

@Data
@ConfigurationProperties("yml.test")//set方法注入属性,在配置类中前缀不支持驼峰,支持羊肉串模式a-b
@ConstructorBinding//构造函数注入属性,需要额外的EnableConfigurationProperties注解开启属性注入,并且不需要加入ioc容器
@Validated//jar303属性校验
public class TestYml {
    private String name;
    private Integer age;

    public TestYml(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

使用@EnableConfigurationProperties来扫描上面的类

@RestController
@EnableConfigurationProperties(TestYml.class)//开启构造函数注入,并且传入要注入的类的class
public class TestController {
    @Autowired
    private TestYml test;
}

以前我们的纯注解的配置都需要在配置类中配置bean,而从SpringBoot2.2.1开始我们可以在非配置类的内部定义Bean加入IOC。


方式3:第三方组件注入

除了使用@ConfigurationProperties 注释类之外,还可以在 public@Bean 方法上使用它。 如果要将属性绑定到不在您控制范围内的第三方组件 依然采用之前的案例的 yaml 配置 创建一个其他组件类

@Data 
public class AnotherComponent { 
private boolean enabled; 
 
private InetAddress remoteAddress; 
}

创建 MyService

@Component 
public class MyService { 

@ConfigurationProperties("acme") //第三方组件注入
@Bean 
public AnotherComponent anotherComponent(){ 
    return new AnotherComponent(); 
	} 
}

通过测试可以获得 AnotherComponent 组件的实例对象。

Value注解绑定

value注解主要用于单个属性的绑定