SpringBoot

SpringBoot

  • SpringBoot基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换
  • 全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率

SpringBoot的特点

  • 为基于Spring的开发提供更快的入门体验
  • 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求
  • 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等
  • SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式

SpringBoot的核心功能

  • 起步依赖
    • 起步依赖本质上是一个Maven项目对象模型(POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能
    • 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能
  • 自动配置
    • Spring Boot的自动配置是一个运行时的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个
    • 该过程是Spring自动完成的

SpringBoot快速入门

  • 创建maven工程(jar)
  • 添加SpringBoot的起步依赖
    • SpringBoot要求,项目要继承SpringBoot的起步依赖spring-boot-starter-parent
    • SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
[XML] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

 

编写SpringBoot引导类
  • 要通过SpringBoot提供的引导类起步SpringBoot才可以进行访问
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
9
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class);
    }
}



  • 编写Controller
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
@RestController
public class QuickStartController {
    @RequestMapping("/quick")
    public String quick() {
        return "springboot 访问成功!";
    }
}

 

  • 访问
  • http://localhost:8080/quick


快速入门解析

  • SpringBoot代码解析
    • @SpringBootApplication
      • 标注SpringBoot的启动类
    • SpringApplication.run(MySpringBootApplication.class) 代表运行SpringBoot的启动类
      • SpringBoot启动类的字节码对象
  • SpringBoot工程热部署
    • 我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样很浪费时间
    • 我们可以在修改代码后不重启就能生效
    • 在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署
    • 注意:IDEA进行SpringBoot热部署失败原因
      • 出现这种情况,并不是热部署配置问题
      • 其根本原因是因为Intellij IEDA默认情况下不会自动编译
      • settint-->compiler-->build project automatically
      • 然后按快捷键: Shift+Ctrl+Alt+/,选择Registry
        • 选中register
        • 勾选compiler.automake.allow.when.app.running
[XML] 纯文本查看 复制代码
1
2
3
4
5
<!--热部署配置-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

 

[Java] 纯文本查看 复制代码
1
settint-->compiler-->build project automatically


SpringBoot原理分析分析spring-boot-starter-parent

  • 按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml,xml配置如下

 

[XML] 纯文本查看 复制代码
1
2
3
4
5
6
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

 

  • 按住Ctrl点击pom.xml中的spring-boot-starter-dependencies,跳转到了 spring-boot-starter-dependencies的pom.xml,xml配置如下
[XML] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<properties>
    <activemq.version>5.15.3</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.63</appengine-sdk.version>
    <artemis.version>2.4.0</artemis.version>
    <aspectj.version>1.8.13</aspectj.version>
    <assertj.version>3.9.1</assertj.version>
    <atomikos.version>4.0.6</atomikos.version>
    <bitronix.version>2.1.4</bitronix.version>
    <build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
    ……
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        ……
</dependencies>
</dependencyManagement>
<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>${kotlin.version}</version>
            </plugin>
            <plugin>
                <groupId>org.jooq</groupId>
                <artifactId>jooq-codegen-maven</artifactId>
                <version>${jooq.version}</version>
            </plugin>
           ………
        </plugins>
    </pluginManagement>
</build>

 

  • 从上面的spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了

spring-boot-starter-web

  • 按住Ctrl点击pom.xml中的spring-boot-starter-web,跳转到了spring-boot-starter-web的pom.xml,xml配置如下
[XML] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starters</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <version>2.0.1.RELEASE</version>
  <name>Spring Boot Web Starter</name>
<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.0.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.0.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.0.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.9.Final</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.0.5.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.5.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

 

  • 从上面的spring-boot-starter-web的pom.xml中我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”
  • 这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作用

自动配置原理解析

  • 按住Ctrl点击查看启动类MySpringBootApplication上的注解@SpringBootApplication
[AppleScript] 纯文本查看 复制代码
1
2
3
4
5
6
@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class);
    }
}

 

  • 注解@SpringBootApplication的源码
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@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 {
 
   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   @AliasFor(annotation = EnableAutoConfiguration.class)
   Class<?>[] exclude() default {};
 
   ……
}

 

  • @SpringBootConfiguration:等同与@Configuration,既标注该类是Spring的一个配置类
  • @EnableAutoConfiguration:SpringBoot自动配置功能开启
  • 按住Ctrl点击查看注解@EnableAutoConfiguration
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ………
}

 

  • 其中,@Import(AutoConfigurationImportSelector.class) 导入了AutoConfigurationImportSelector类
  • 按住Ctrl点击查看AutoConfigurationImportSelector源码
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   "List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);"
   configurations = removeDuplicates(configurations);
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
   configurations = filter(configurations, autoConfigurationMetadata);
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return StringUtils.toStringArray(configurations);
}
 
protected List<String> "getCandidateConfigurations"(AnnotationMetadata metadata,
      AnnotationAttributes attributes) {
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
         getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
   Assert.notEmpty(configurations,
         "No auto configuration classes found in 'META-INF/spring.factories'. If you "
               + "are using a custom packaging, make sure that file is correct.");
   return configurations;
}

 

  • 其中,SpringFactoriesLoader.loadFactoryNames方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表
  • spring.factories 文件中有关自动配置的配置信息如下
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
……
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.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,\
……

 

  • 上面配置文件存在大量的以Configuration为结尾的类名称,这些类就是存有自动配置信息的类,而 SpringApplication在获取这些类名后再加载
  • 我们以ServletWebServerFactoryAutoConfiguration为例来分析源码
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
    "… … …"
}

 

  • 其中,@EnableConfigurationProperties(ServerProperties.class)代表加载ServerProperties服务器配置属性类
  • 进入ServerProperties.class源码如下
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
   /**Server HTTP port. */
   private Integer port;
   /**Network address to which the server should bind. */
   private InetAddress address;
   … … …
}



更多免费技术资料可关注:annalin1203

posted @ 2020-05-18 09:01  幽暗森林之猪大屁  阅读(127)  评论(0)    收藏  举报