SpringBoot 学习笔记

SpringBoot 概述

Spring 为开发 Java 应用程序提供了全面的基础架构支持,它将 Java 对象交由容器统一管理,从而实现控制反转(IOC)和依赖注入(DI),并提供了一些常用模块如 SpringAOP、SpringJDBC、SpringMVC 等等

SpringBoot 继承了 Spring 的核心思想,并进一步简化应用开发,其特性如下:

  1. SpringBoot 提供 Starter 并结合自动配置,主流框架无需配置就可以开箱即用
  2. SpringBoot简化了开发,基于约定大于配置的思想,使用无 xml
  3. SpringBoot 内置 Web 容器,直接运行 jar 文件即可启动 Web 应用
  4. SpringBoot 帮助管理常用的第三方依赖的版本,减少版本冲突
  5. SpringBoot 自带监控功能,可以监控应用程序的运行状况

Spring 与 SpringBoot 的区别?

Spring 和 SpringBoot 都是 Spring 生态的产品,Spring 是一个容器框架,SpringBoot 不是一个框架,是一个可以快速构建基于 Spring 的脚手架(里面包含 Spring 和各种框架)


SpringBoot 自动装配

SpringBoot 的自动配置(Auto Configuration)旨在简化 Spring 应用程序的配置过程

在了解自动装配前首先要了解 SpringBoot Starters,其是一组预配置的依赖集合,用于启用特定类型的功能。例如,通过引入 spring-boot-starter-web 启用 Web 功能,包括内嵌的 Web 服务器、SpringMVC 等,而无需单独处理每个依赖的版本和配置,简化依赖管理

SpringBoot Starters 还提供与功能相关的自动配置类,SpringBoot 启动时会自动扫描并加载类路径上的自动配置类,实现自动装配。SpringBoot 的自动配置还涉及到条件化配置,这意味着配置仅在特定条件满足时才会生效,例如,只有在类路径上存在特定的库,获取特定的 Bean 已经存在,相关的配置才会被自动应用

尽管 SpringBoot 提供了自动配置,但仍然可以根据需要自定义。通过提供自定义配置覆盖默认的自动配置,或者通过配置文件修改自动配置的行为

SpringBoot 自动装配流程如下:

  1. 通过 @SpringBootConfiguration 引入了 @EnableAutoConfiguration,该注解负责启动自动配置功能
  2. @EnableAutoConfiguration 引入 @Import 注解
  3. Spring 容器启动时会解析 @Import 注解
  4. @Import 导入一个 deferredlmportSelector,它会使 SpringBoot 的自动配置类的顺序排在最后,方便我们扩展和覆盖
  5. 读取所有 /META-INF/spring.factories 文件
  6. 获取所有 AutoConfigurtionClass 类型的自动配置类
  7. 通过 @Condition 排除无效的自动配置类

SpringBoot 启动步骤

SpringBoot 启动步骤大致简化如下:

  1. 加载启动类:SpringBoot 应用的入口是一个 Java 类,通常带有 main 方法,这个类被称为启动类
  2. 构建应用程序上下文:启动类中的 main 方法通常会使用 SpringApplication.run()方法构建 SpringBoot 应用上下文
  3. 自动配置:在构建应用程序上下文的过程中,SpringBoot 会自动扫描类路径上的自动配置类,进行自动配置
  4. 加载外部属性:SpringBoot 会加载各种外部属性文件,包括 application.properties 或 application.yml,这些文件中包含应用程序的配置信息
  5. 创建 Bean 实例:SpringBoot 使用容器来管理应用程序中的 Bean 实例。在应用程序上下文构建过程中,SpringBoot 会创建和管理这些 Bean
  6. 启动内嵌服务器:如果应用程序是 Web 应用,SpringBoot 会在启动过程中自动配置和启动内嵌的 Web 服务器(比如 Tomcat)
  7. 执行初始化和回调:在应用程序上下文构建完成后,SpringBoot 会执行各种初始化和回调操作,例如调用 ApplicationRunner 或 CommandLineRunner 实现类的方法,以执行一些应用程序启动时的逻辑
  8. 应用程序运行:一旦应用程序上下文构建完成,Web 服务器启动并监听请求,应用程序便开始运行,等待客户端请求

在启动过程中,SpringBoot 还会发布与生命周期相关的事件,可以通过监听这些事件完成对应的操作


SpringBoot 条件注解

条件注解会判断预定义的条件是否成立,如果条件成立,则相应的组件或配置会被启用,否则会被忽略。这使得开发人员能够根据应用程序的环境、依赖和配置来动态地调整应用程序的行为。条件注解也是 SpringBoot 自动装配的核心机制

常见的 SpringBoot 条件注解及其用途如下:

  1. @ConditionalOnClass:当指定的类位于类路径上时,才会启用被注解的组件或配置,可用于根据类的可用性来决定是否启用某个特定功能
  2. @ConditionalOnMissingClass:当指定的类不在类路径上时,才会启用被注解的组件或配置,可用于在某些类不可用时的备用实现
  3. @ConditionalOnBean:当指定的 Bean 在应用程序上下文中存在时,才会启用被注解的组件或配置,可用于基于其他 Bean 存在与否来决定是否启用特定功能
  4. @ConditionalOnMissingBean:当指定的 Bean 在应用程序上下文中不存在时,才会启用被注解的组件或配置,可用于提供默认实现或避免重复创建 Bean
  5. @ConditionalOnProperty:当指定的属性满足条件时,才会启用被注解的组件或配置,可用于基于配置属性的值来决定是否启用特定功能
  6. @ConditionalOnExpression:当指定的 SpEL 表达式计算结果为 true 时,才会启用被注解的组件或配置,可用于复杂的条件判断

SpringBoot Jar 包启动原理

SpringBoot 应用程序可以打包为可执行的 JAR 文件并直接运行,这是因为 SpringBoot 将应用程序的所需的依赖、配置和运行环境都被封装在了 JAR 文件中,从而实现了轻量级、自包含的可执行文件

SpringBoot 提供了 SpringBoot Maven 插件,可以方便地将应用程序打包为可执行的 JAR 文件,这个 JAR 文件包含应用本身的 JAR 以及对应依赖的 JAR 包。运行该 JAR 文件实际运行的是 JarLauncher 类的 main 方法,其负责创建一个 LaunchedURLClassLoader 来加载 boot-lib 下面的 JAR,并以一个新线程启动应用的 main 方法。创建一个新的类加载器是因为通过 SpringBoot 生成的 JAR 文件中包含了其他资源的 JAR,而 Java 默认的类加载器无法从 JAR 文件中再去加载其他 JAR 文件


SpringBoot 配置优先级

SpringBoot 应用程序在启动时会遵循下面的顺序进行加载配置文件:

  1. 类路径下的配置文件
  2. 类路径内 config 子目录的配置文件
  3. 当前项目根目录下的配置文件
  4. 当前项目根目录下 config 子目录的配置文件

示例项目配置文件存放结构如下所示:

. project-sample
├── config
│   ├── application.yml (4)
│   └── src/main/resources
|   │   ├── application.yml (1)
|   │   └── config
|   |   │   ├── application.yml (2)
├── application.yml (3)

启动时加载配置文件顺序:1 > 2 > 3 > 4,也就是说优先级是 4 > 3 > 2 >1,因为 SpringBoot 是按顺序加载的,后面的配置会覆盖前面的配置

SpringBoot 支持 properties 和 yaml 两种类型的配置文件,其中 properties 优先级高于 yaml,同一目录层级同时存在 properties 和 yaml 并存在相同配置时,前者会覆盖后者。如果在启动时存在命令行参数,那么将覆盖配置文件的值


spring.factories 文件的作用

spring.factories 文件是 Spring 的一个机制,用于实现在类路径下自动发现和加载扩展点的功能

Spring 会在类路径下搜索并加载 spring.factories 文件,并根据文件中的配置自动发现扩展点。这些扩展点可以是自定义的类、接口或配置类,用于提供额外的功能、特性或行为

SpringBoot 运行时会去寻找 META-INF/spring.factories 文件,以 mybatis-plus 为例,当引入对应的 starters 时,其中同样存在 META-INF/spring.factories 文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
  \com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,
  \com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration

其中 MybatisPlusAutoConfiguration 为自动配置类,SpringBoot 会从该文件获取 MybatisPlusAutoConfiguration 类从而实现自动装配


SpringBoot Cglib 动态代理

Spring Boot 默认使用 Cglib 动态代理,原因如下:

  1. 性能和速度:Cglib 直接通过字节码生成子类实现代理,更加高效
  2. 无需接口:JDK 动态代理要求目标类必须实现一个接口,而 Cglib 动态代理不需要,扩展了动态代理的适用范围
  3. 无侵入性:Cglib 动态代理可以使类无需实现任何接口或继承特定的类,从而减少了对源代码的侵入性
  4. 方便集成:SpringBoot 默认提供 Cglib 相关依赖

@SpringBootApplication 注解

@SpringBootApplication 注解是 SpringBoot 中的一个核心注解,用于标识一个 SpringBoot 应用程序类,理解该注解需要从以下几个方面考虑:

  1. 组合注解:@SpringBootApplication 实际上是一个组合注解,包含多个其他注解,用于快速配置和启动一个 SpringBoot 应用程序,其包括了以下三个注解的功能:

    • @SpringBootConfiguration:标识该类为 SpringBoot 配置类,类似于 @Configuration
    • @EnableAutoConfiguration:启用自动配置,用来加载类路径下的自动配置类
    • @ComponentScan:扫描当前包及其子包,查找带有 Spring 相关注解(@Component、@Service、@Controller 等)的类,将它们注册为 Bean,这里会排除自动配置类
  2. 主程序入口:@SpringBootApplication 注解通常被标注在应用程序的主类,即包含 main 方法的类,代表应用程序的入口点,通过执行 main 方法来启动 SpringBoot 应用

  3. 约定大于配置:@SpringBootApplication 注解代表了 SpringBoot 的约定大于配置的思想,它默认会启用自动配置,扫描并注册需要的组件,从而使得应用程序的配置过程变得简单

  4. 配置扩展:尽管 @SpringBootApplication 注解已经包含了许多默认的配置,但仍可以在应用程序中添加自己的配置类,自定义 Bean 和其他相关组件,进一步定制和扩展应用程序的行为


SpringBoot 内置 Tomcat 启动原理

当引入 Spring-boot-starter-web 依赖时会在 SpringBoot 中添加 ServletWebServerFactoryAtutoConfiguration 自动配置类,该类通过 @Import 导入了可用(通过 @ConditionalOnClass 判断决定使用哪一个)的 Web 容器工厂(默认 Tomcat),在 SpringBoot 启动时找到 Web 容器工厂创建内嵌的 Tomcat 并将其启动


SpringBoot 自定义 starter

第一步:创建一个 starter 项目,推荐命名格式为 {xxxx}-spring-boot-starter,比如 mybatis-spring-boot-starter

新建一个 Maven 项目,实现发送短信功能,设置 pom.xml 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>sms-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starters</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <dependencies>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>

    </dependencies>

</project>

第二步:创建 ConfigurationProperties 用于保存配置信息(如果项目不使用配置信息则可以跳过这一步)

@ConfigurationProperties(prefix = "sms")
@Data
public class SmsProperties {

    private SmsMessage aliyun = new SmsMessage();

    private SmsMessage tencent = new SmsMessage();

    @Data
    public static class SmsMessage{


        /**
         * 用户名
         */
        private String userName;

        /**
         * 密码
         */
        private String passWord;

        /**
         * 秘钥
         */
        private String sign;

        /**
         *
         */
        private String url;

        @Override
        public String toString() {
            return "SmsMessage{" +
                    "userName='" + userName + '\'' +
                    ", passWord='" + passWord + '\'' +
                    ", sign='" + sign + '\'' +
                    ", url='" + url + '\'' +
                    '}';
        }
    }
}

其他项目只需要在配置文件中配置 SmsProperties 的属性信息就可以了:

sms:
  aliyun:
    pass-word: 12345
    user-name: java金融
    sign: 阿里云
    url: http://aliyun.com/send
  tencent:
    pass-word: 6666
    user-name: java金融
    sign: 腾讯云
    url: http://tencent.com/send

第三步:创建自动配置类和实现类,并在 spring.factories 配置文件中声明自动配置类

自动配置类

@EnableConfigurationProperties(value = SmsProperties.class)
@Configuration
public class SmsAutoConfiguration  {
    /**
     *  阿里云发送短信的实现类
     * @param smsProperties
     * @return
     */
    @Bean
    public AliyunSmsSenderImpl aliYunSmsSender(SmsProperties smsProperties){
       return new AliyunSmsSenderImpl(smsProperties.getAliyun());
    }
    /**
     * 腾讯云发送短信的实现类
     * @param smsProperties
     * @return
     */
    @Bean
    public TencentSmsSenderImpl tencentSmsSender(SmsProperties smsProperties){
        return new TencentSmsSenderImpl(smsProperties.getTencent());
    }
}

Bean 实现类

public class AliyunSmsSenderImpl implements SmsSender {

    private SmsMessage smsMessage;

    public AliyunSmsSenderImpl(SmsMessage smsProperties) {
        this.smsMessage = smsProperties;
    }

    @Override
    public boolean send(String message) {
        System.out.println(smsMessage.toString()+"开始发送短信==》短信内容:"+message);
        return true;
    }
}

在 resources 文件夹下新建目录 META-INF,在目录中新建 spring.factories 文件,并且在 spring.factories 中配置AutoConfiguration, value 是 SmsAutoConfiguration 全限定名:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.xxx.SmsAutoConfiguration

第四步:打包 starter 项目,在需要的项目中引入该 starter 依赖,就可以使用了

posted @ 2024-03-25 16:15  低吟不作语  阅读(204)  评论(0编辑  收藏  举报