SpringBoot2入门篇

1.入门篇

1.1、基础

01、基础入门-SpringBoot2课程介绍

  • 学习要求
    -熟悉Spring基础
    -熟悉Maven使用
  • 环境要求
    • Java8及以上
    • Maven 3.3及以上

02、基础入门-Spring生态圈

spring官网:https://spring.io/

Spring能做什么

Spring的能力
Spring Boot 介绍

Spring Boot 可帮助您创建可以运行的独立的、生产级的基于 Spring 的应用程序。我们对 Spring 平台和第三方库持固执己见的看法,以便您可以轻松上手。大多数 Spring Boot 应用程序只需要很少的 Spring 配置。

您可以使用 Spring Boot 创建可以通过使用java -jar或更传统的战争部署启动的 Java 应用程序。我们还提供了一个运行“spring 脚本”的命令行工具。

我们的主要目标是:

  • 为所有 Spring 开发提供从根本上更快且可广泛访问的入门体验。
  • 开箱即用,但随着需求开始偏离默认值,请迅速摆脱困境。
  • 提供一系列大型项目通用的非功能特性(例如嵌入式服务器、安全性、指标、健康检查和外部化配置)。
  • 绝对没有代码生成,也不需要 XML 配置。

image-20220304154633076

Spring的生态

覆盖了:

  • web开发
  • 数据访问
  • 安全控制
  • 分布式
  • 消息服务
  • 移动开发
  • 批处理
Spring5重大升级
  • 响应式编程

image-20220304154712117

  • 内部源码设计

基于Java8的一些新特性,如:接口默认实现。重新设计源码架构。

为什么用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缺点

人称版本帝,迭代快,需要时刻关注变化
封装太深,内部原理复杂,不容易精通

03、基础入门-SpringBoot的大时代背景

微服务

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
					——James Lewis and Martin Fowler (2014)
  • 微服务是一种架构风格
  • 一个应用拆分为一组小型服务
  • 每个服务运行在自己的进程内,也就是可独立部署和升级
  • 服务之间使用轻量级HTTP交互
  • 服务围绕业务功能拆分
  • 可以由全自动部署机制独立部署
  • 去中心化,服务自治。服务可以使用不同的语言、不同的存储技术

分布式

image-20220304160448114
分布式的困难
  • 远程调用
  • 服务发现
  • 负载均衡
  • 服务容错
  • 配置管理
  • 服务监控
  • 链路追踪
  • 日志管理
  • 任务调度
分布式的解决
  • SpringBoot + SpringCloud

image-20220304160514525

云原生

原生应用如何上云。 Cloud Native

上云的困难
  • 服务自愈
  • 弹性伸缩
  • 服务隔离
  • 自动化部署
  • 灰度发布
  • 流量治理
上云的解决

image-20220304160747118

04、基础入门-SpringBoot官方文档架构

官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/

image-20220304162738583

image-20220304162803118

查看版本新特性

image-20220304163006781

05、基础入门-SpringBoot-HelloWorld

5.1 第一个springboot程序

修改maven的配置文件 conf/setting.xml

<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>
    <!--编译JDK版本-->
	<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>

创建Springboot工程-IDEA

image-20220304165147352 image-20220304165249697

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!--引用springboot父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.4</version>
    </parent>

    <groupId>com.lebrwcd</groupId>
    <artifactId>SpringBoot-atguigu</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <!--springboot-web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--springboot项目依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--简化部署,打成jar包直接包含整个springboot环境-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Boot提供了许多“启动器”,让您可以将JAR添加到类路径中。我们的测试应用程序使用POM父部分中的spring boot starter父项。spring boot starter parent是一个特殊的启动程序,它提供了有用的Maven默认值。它还提供了一个依赖项管理部分,以便您可以省略依赖项的版本标记。

其他“Starter”提供开发特定类型应用程序时可能需要的依赖项。因为我们正在开发一个web应用程序,所以我们添加了一个spring boot starter web依赖项。在此之前,我们可以通过运行以下命令来查看当前的情况:

测试程序:

/*@Controller
@ResponseBody

@RestController = @ResponseBody + @Controller

*/
@RestController
public class TestController {
    
    @RequestMapping("/hello")
    public String hello(){
        return "hello Spring boot 2!";
    }
}

MyApplication我们类的第一个注释是@RestController. 这称为构造型注释。它为阅读代码的人和 Spring 提供了类扮演特定角色的提示。在这种情况下,我们的类是一个 web @Controller,因此 Spring 在处理传入的 Web 请求时会考虑它。

@RequestMapping注释提供“路由”信息。它告诉 Spring 任何带有该/路径的 HTTP 请求都应该映射到该home方法。注释告诉 Spring将@RestController结果字符串直接呈现给调用者。

主程序:

/**
	@SpringBootApplication : 告诉说这是一个springboot程序
*/
@SpringBootApplication
public class SpringBootAtApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootAtApplication.class, args);
    }
}

我们应用程序的最后一部分是main方法。这是一种遵循应用程序入口点的 Java 约定的标准方法。我们的 main 方法通过调用委托给 Spring Boot 的SpringApplicationrunSpringApplication引导我们的应用程序,启动 Spring,然后启动自动配置的 Tomcat Web 服务器。我们需要将MyApplication.class作为参数传递给该run方法,以判断SpringApplication哪个是主要的 Spring 组件。该args数组也被传递以公开任何命令行参数。

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v2.6.4)
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 2.222 seconds (JVM running for 6.514)

设置配置

maven工程的resource文件夹中创建application.properties文件。

#设置端口号
server.port=8888
image-20220304201621970
5.2 打包部署

我们通过创建一个可以在生产中运行的完全独立的可执行 jar 文件来完成我们的示例。可执行 jars(有时称为“fat jars”)是包含已编译类以及代码需要运行的所有 jar 依赖项的存档。

<packaging>jar</packaging>
springboot工程默认是jar

在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包,

--- maven-jar-plugin:3.2.2:jar (default-jar) @ SpringBoot-atguigu ---
[INFO] Building jar: D:\IntelliJ IDEA\IntelliJ IDEA 2021.1.1\projeces\SpringBoot-atguigu\target\SpringBoot-atguigu-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.6.4:repackage (repackage) @ SpringBoot-atguigu ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------

image-20220304202445380

打包好的jar包被生成在helloworld工程项目的target文件夹内。

用cmd运行java -jar jar包名,既可以运行helloworld工程项目。

将jar包直接在目标服务器执行即可。

image-20220304202742632

和以前一样,要退出应用程序,请按ctrl-c

注意:cmd窗口要关闭快速编辑模式

image-20220304203018731

06、基础入门-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:

    Starters 是一组方便的依赖描述符,您可以将其包含在您的应用程序中。您可以获得所需的所有 Spring 和相关技术的一站式商店,而无需搜索示例代码和复制粘贴加载的依赖描述符。例如,如果您想开始使用 Spring 和 JPA 进行数据库访问,请将spring-boot-starter-data-jpa依赖项包含在您的项目中。

    启动器包含许多依赖项,您需要这些依赖项使项目快速启动并运行,并具有一致的、受支持的托管传递依赖项集

  • 开发导入starter场景启动器

    • 见到很多 spring-boot-starter-* : *就某种场景
    • 只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
    • 更多SpringBoot所有支持的场景https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
    • 见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
所有场景启动器最底层的依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter</artifactId>
	<version>2.3.4.RELEASE</version>
	<scope>compile</scope>
</dependency>
  • 无需关注版本号,自动版本仲裁
    1. 引入依赖默认都可以不写版本
    2. 引入非版本仲裁的jar,要写版本号。
  • 可以修改默认版本号
    1. 查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
    2. 在当前项目里面重写配置,如下面的代码。
<properties>
	<mysql.version>5.1.43</mysql.version>
</properties>

IDEA快捷键:

  • ctrl + shift + alt + U:以图的方式显示项目中依赖之间的关系。

    image-20220304205517313
  • alt + ins:相当于Eclipse的 Ctrl + N,创建新类,新包等。

07、基础入门-SpringBoot-自动配置特性

  • 自动配好Tomcat

    • 引入Tomcat依赖。

    • 配置Tomcat

    • 自动配好SpringMVC

      • 引入SpringMVC全套组件
      • 自动配好SpringMVC常用组件(功能)
    • 自动配好Web常见功能,如:字符编码问题

      • SpringBoot帮我们配置好了所有web开发的常见场景
      <!--springboot-web起步依赖-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      

​ spring-boot-starter-web中的依赖项

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.6.4</version>
    <scope>compile</scope>
  </dependency>
    
  <!--json-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>2.6.4</version>
    <scope>compile</scope>
  </dependency>
    
  <!--Tomcat-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>2.6.4</version>
    <scope>compile</scope>
  </dependency>
    
  <!--web-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.16</version>
    <scope>compile</scope>
  </dependency>
    
  <!--webmvc-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.16</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

run方法的返回值是IOC容器

@SpringBootApplication
public class SpringBootAtguiguApplication {

    public static void main(String[] args) {
		
        //1.获得IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootAtguiguApplication.class, args);
        //2.获得IOC中容器组件名称
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

有以前web开发中需要用到的DispatcherServlet、CharacterEncoidngFilter,viewSolver…

image-20220305093851995image-20220305093914220

image-20220305094011131
  • 默认的包结构

    • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来

      image-20220305094130195
    • 无需以前的包扫描配置

    • 想要改变扫描路径

      • @SpringBootApplication(scanBasePackages=“com.lun”)
      • @ComponentScan 指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.lebrwcd") //springBootApplication默认扫描的包是主程序所在包
  • 各种配置拥有默认值

      • 默认配置最终都是映射到某个类上,如:ReactiveMultipartProperties

        spring.webflux.multipart.file-storage-directory=
        

        image-20220305094604221

      • 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象

  • 按需加载所有自动配置项

    • 非常多的starter
    • 引入了哪些场景这个场景的自动配置才会开启
    • SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面

    image-20220306090045343

1.2、底层注解

08、底层注解-@Configuration详解

以前注册bean对象是用的xml配置文件

<bean id="user" class="com.lebrwcd.domain.User"/>
<bean id="cat" class="com.lebrwcd.domain.Cat"/>

现在可以采用配置类,在类上加上@Configuration注解

image-20220305103752559
/**
 * @Configuration  : 告诉springboot这是一个配置类 == 配置文件
 *          1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
 *          2、配置类本身也是组件
 *          3、proxyBeanMethods:代理bean的方法
 *                Full(proxyBeanMethods = true)(保证每个@Bean方法被调用多少次返回的组件都是单实例的)(默认)
 *                Lite(proxyBeanMethods = false)(每个@Bean方法被调用多少次返回的组件都是新创建的)
 *
 */
@Configuration(proxyBeanMethods = true)
public class MyConfig {


    /**
     * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
     * @Bean : 给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
     *       可修改beanId,采用属性name
     *
     */
    @Bean
    public User user01(){
        User user = new User("wcd",18);
        user.setCat(cat());
        return user;
    }
    
    @Bean("tom")
    public Cat cat(){
        return new Cat("tom");
    }
}
@SpringBootApplication
public class SpringBootAtguiguApplication {

    public static void main(String[] args) {

        //1.获取IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootAtguiguApplication.class, args);

        //2.遍历IOC中组件名
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        //3.从容器中获取组件
        User user = run.getBean("user01", User.class);
        User user1 = run.getBean("user01", User.class);
        System.out.println(user == user1);      //true,单实例

        //4.配置类本身也是组件
        MyConfig myConfig = run.getBean(MyConfig.class);
        System.out.println(myConfig);
        //com.lebrwcd.config.MyConfig$$EnhancerBySpringCGLIB$$aff39f54@2e1792e7  经过CGLIB代理的对象

        //如果@Configuration(proxyBeanMethods = true)[默认]代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
        User user2 = myConfig.user01();
        User user3 = myConfig.user01();
        System.out.println(user2 == user3); //true


        User user4 = run.getBean("user01",User.class);
        Cat cat = run.getBean("tom", Cat.class);

        System.out.println(user4.getCat() == cat);  //true 组件依赖
    }
}
  • 最佳实战
    • 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
    • 配置 类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(默认)
09、底层注解-@Import导入组件

@Bean、@Component、@Controller、@Service、@Repository,它们是Spring的基本标签,在Spring Boot中并未改变它们原来的功能。

@Import({User.class,})给容器中自动创建出这个类型的组件、默认组件的名字就是全限定类名

测试:

@Import({User.class})
@Configuration()
public class MyConfig {
System.out.println("=====================");
String[] userArray = run.getBeanNamesForType(User.class);
for (String s : userArray) {
    System.out.println(s);
}
//com.lebrwcd.domain.User
//user01
10、底层注解-@Conditional条件装配

条件装配:满足Conditional指定的条件,则进行组件注入

image-20220305105943353

采用@ConditionalOnBean举例

主程序类:

boolean tom = run.containsBean("tom");
System.out.println("tom组件:" + tom);

boolean user01 = run.containsBean("user01");
System.out.println("tom组件:" + user01);
没有加@Conditional之前
	@Bean
    public User user01(){
        User user = new User("wcd",18);
        user.setCat(cat());
        return user;
    }

//    @Bean("tom")
    public Cat cat(){
        return new Cat("tom");
    }

结果是:

image-20220305110411540

@ConditionalOnBean
    
    @ConditionalOnBean(name = "tom")  //表示有这个名为tom的bean才注册user01对象
	@Bean
    public User user01(){
        User user = new User("wcd",18);
        user.setCat(cat());
        return user;
    }

//    @Bean("tom")
    public Cat cat(){
        return new Cat("tom");
    }

image-20220305110630411

    @Bean("tom")
    public Cat cat(){
        return new Cat("tom");
    }

    @ConditionalOnBean(name = "tom")  //表示有这个名为tom的bean才注册user01对象
    @Bean
    public User user01(){
        User user = new User("wcd",18);
        user.setCat(cat());
        return user;
    }


image-20220305111047325

注意有先后顺序,如果注册tom的在注册user01的下面,即使注册了tom的,user01还是没有注册上

@ConditionalOnBean(name = "tom")  //表示有这个名为tom的bean才注册user01对象
@Bean
public User user01(){
    User user = new User("wcd",18);
    user.setCat(cat());
    return user;
}

@Bean("tom")
public Cat cat(){
    return new Cat("tom");
}

image-20220305110931503

如果把@ConditionalOnBean放在类上,则表示类里的所有bean注册需要满足某条件才能注册

如果把@ConditionalOnMissingBean放在类上,则表示类里的所有bean注册需要不满足某条件才能注册

@Configuration()
@ConditionalOnBean(name = "tom")  //表示容器中有这个名为tom的bean才注册该配置类中的所有bean
public class MyConfig {
@Configuration()
@ConditionalOnMissingBean(name = "tom")  //表示容器中没有这个名为tom的bean才注册该配置类中的所有bean
public class MyConfig {
11、底层注解-@ImportResource导入Spring配置文件

比如,公司使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource粉墨登场。

bean.xml:

<bean id="user" class="com.lebrwcd.domain.User">
        <property name="name" value="wcd"/>
        <property name="age" value="12"/>
        <property name="cat" ref="tom"/>
    </bean>

    <bean id="tom" class="com.lebrwcd.domain.Cat">
        <property name="name" value="dd"/>
    </bean>

使用方法:

@ImportResource("classpath:beans.xml")
public class MyConfig {
...
}

12、底层注解-@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

@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {

    private String brand;
    private Integer price;
    ...
}

Spring Boot另一种配置配置绑定:

@EnableConfigurationProperties + @ConfigurationProperties

@EnableConfigurationProperties注在配置类上,作用:

  1. 开启Car配置绑定功能
  2. 把这个Car这个组件自动注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {
//@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {

1.3、自动配置

13、自动配置【源码分析】-自动包规则原理

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 {};
}
  1. 利用Registrar给容器中导入一系列组件
  2. 将指定的一个包下的所有组件导入进MainApplication所在包下。

14、自动配置【源码分析】-初始加载自动配置类

@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位置来加载一个文件。

    1. 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件

    2. 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() {
          }
      	...
      }
      

15、自动配置【源码分析】-自动配置流程

DispatcherServletAutoConfiguration的内部类DispatcherServletConfiguration为例子:

@AutoConfigureOrder(-2147483648)
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({DispatcherServlet.class})
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
public class DispatcherServletAutoConfiguration {
    //dispathcerServlet
    @Configuration(
        proxyBeanMethods = false   告诉springboot这是一个配置类
    )
    @Conditional({DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition.class})
    @ConditionalOnClass({ServletRegistration.class})
    @EnableConfigurationProperties({WebMvcProperties.class})
    protected static class DispatcherServletConfiguration {
        protected DispatcherServletConfiguration() {
        }

        //在容器中注册对象,bean的名字为dispatherServlet
        @Bean(
            name = {"dispatcherServlet"}
        )
        public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
            dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
       dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
            dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
            dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
            return dispatcherServlet;
        }
    
		//文件上传解析器
        @Bean
        @ConditionalOnBean({MultipartResolver.class})//容器中有这个类型组件
        @ConditionalOnMissingBean(
            name = {"multipartResolver"}//容器中没有这个名字 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先加载所有的自动配置类 xxxAutoConfiguration

  • 每个自动配置类按照@Conditional…条件进行生效,默认都会绑定配置文件xxxproperties指定的值(xxxProperties里面读取,xxxProperties和配置文件进行了绑定)

  • 生效的配置类就会给容器加载很多组件(比如上面的DispatcherServletAutoConfiguration生效后就加载dispatherServlet组件和文件上传解析器组件等)

  • 只要容器中有这些组件,相当于这些功能就有了

  • 定制化配置

    • 用户直接自己@Bean替换底层的组件(在自己的Configuration类上@Bean)

    • 用户去看这个组件获取的配置文件什么值去核心配置文件修改

      image-20220305205256280
image-20220305205314990

​ 这是Spring Boot另一种配置文件与配置类映射绑定:

​ @EnableConfigurationProperties+@ConfigurationProperties`

​ @EnableConfigurationProperties注在配置类上,作用:开启类的配置绑定功能;把这个类中的这个组件自动注册到容器中

image-20220305205340204

自动配置流程:xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties

1.4、最佳实践

16、最佳实践-SpringBoot应用如何编写
  • 引入场景依赖

  • 查看自动配置了哪些(选做)

    • 自己分析,引入场景对应的自动配置一般都生效了

    • 核心配置文件中debug=true开启自动配置报告

      debug=true
      
      • Negative(不生效)

      • Positive(生效)

        Positive matches:
        -----------------
        
           xxxConfiguration matched:
        
        Negative matches:
        -----------------
        
           xxxAutoConfiguration:
              Did not match:
        
        
  • 是否需要修改

    • 参照文档修改配置项

      • 官方文档

      []: https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties

      • 自己分析。xxxxProperties绑定了配置文件的哪些。
    • 自定义加入或者替换组件

      • @Bean、@Component…

17、最佳实践-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		//setter and getter
@ToString  //ToString
@EqualsAndHashCode  //Equals  and  HashCode
public class User {

    private String name;
    private Integer age;
    private Pet pet;
}

简化日志开发

@Slf4j

@RestController
@Slf4j
public class TestController {
    @RequestMapping("/hello")
    public String hello(){
        log.info("请求进来了");
        return "hello Spring boot 2!";
    }
}

image-20220306085828624

18、最佳实践-dev-tools
spring-boot-devtools每当类路径上的文件更改时,使用自动重新启动的应用程序。在 IDE 中工作时,这可能是一个有用的功能,因为它为代码更改提供了一个非常快速的反馈循环。默认情况下,类路径上指向目录的任何条目都会被监视更改。请注意,某些资源,例如静态资产和视图模板,不需要重新启动应用程序。

触发重启
由于 DevTools 监控类路径资源,触发重启的唯一方法是更新类路径。更新类路径的方式取决于您使用的 IDE:

在 Eclipse 中,保存修改后的文件会导致类路径更新并触发重新启动。

在 IntelliJ IDEA 中,构建项目 ( Build +→+ Build Project)  ctrl+F9 具有相同的效果。

如果使用构建插件,mvn compile为 Maven 或gradle buildGradle 运行将触发重新启动。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

在IDEA19、最佳实践-Spring Initailizr中,项目或者页面修改以后:Ctrl+F9。自动重新编译功能哪个页面或者文件修改了,都要ctrl+f9

19、最佳实践-Spring Initailizr

Spring Initailizr是创建Spring Boot工程向导。

在IDEA中,菜单栏New -> Project -> Spring Initailizr。

image-20220306091443634

image-20220306091724759

age;
private Pet pet;
}


**简化日志开发**

`@Slf4j`

```java
@RestController
@Slf4j
public class TestController {
    @RequestMapping("/hello")
    public String hello(){
        log.info("请求进来了");
        return "hello Spring boot 2!";
    }
}

[外链图片转存中…(img-iuOJ2QXc-1648084740955)]

18、最佳实践-dev-tools
spring-boot-devtools每当类路径上的文件更改时,使用自动重新启动的应用程序。在 IDE 中工作时,这可能是一个有用的功能,因为它为代码更改提供了一个非常快速的反馈循环。默认情况下,类路径上指向目录的任何条目都会被监视更改。请注意,某些资源,例如静态资产和视图模板,不需要重新启动应用程序。

触发重启
由于 DevTools 监控类路径资源,触发重启的唯一方法是更新类路径。更新类路径的方式取决于您使用的 IDE:

在 Eclipse 中,保存修改后的文件会导致类路径更新并触发重新启动。

在 IntelliJ IDEA 中,构建项目 ( Build +→+ Build Project)  ctrl+F9 具有相同的效果。

如果使用构建插件,mvn compile为 Maven 或gradle buildGradle 运行将触发重新启动。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

在IDEA19、最佳实践-Spring Initailizr中,项目或者页面修改以后:Ctrl+F9。自动重新编译功能哪个页面或者文件修改了,都要ctrl+f9

19、最佳实践-Spring Initailizr

Spring Initailizr是创建Spring Boot工程向导。

在IDEA中,菜单栏New -> Project -> Spring Initailizr。

[外链图片转存中…(img-AxVkcEBU-1648084740956)]

[外链图片转存中…(img-qIlydiKd-1648084740956)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值