Skip to content

SpringBoot

打包和部署

非 Docker

详细用法请参考示例 https://gitee.com/dexterleslie/demonstration/tree/master/demo-spring-boot/demo-spring-boot-mvc

打包

bash
./mvnw package -Ddockerfile.skip=false

启动应用

bash
java -jar target/demo-spring-boot-mvc-0.0.1-SNAPSHOT.jar

访问http://localhost:8080/hello返回 Hello! 表示应用运行正常

基于 Docker

详细用法请参考示例 https://gitee.com/dexterleslie/demonstration/tree/master/demo-spring-boot/demo-spring-boot-mvc

Dockerfile 内容如下:

dockerfile
#FROM openjdk:8-jdk-slim
FROM openjdk:17-jdk-slim

ADD target/demo.jar /usr/share/demo.jar

ENV JAVA_OPTS=""

ENTRYPOINT java ${JAVA_OPTS} -jar /usr/share/demo.jar --spring.profiles.active=prod

docker-compose.yaml 内容如下:

yaml
version: "3.0"

services:
  demo:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - JAVA_OPTS= -Xmx512m
      - TZ=Asia/Shanghai
    image: registry.cn-hangzhou.aliyuncs.com/future-public/demo-spring-boot-mvc
    ports:
      - "8080:8080"

build.sh 内容如下:

bash
#!/bin/bash

set -e

./mvnw package -Dmaven.test.skip=true

docker compose build

push.sh 内容如下:

bash
#!/bin/bash

set -e

docker compose push

SpringBoot Starter

SpringBoot Starter是一组方便的依赖组合,用于简化Spring项目中的依赖管理。以下是对Spring Boot Starter的详细介绍:

一、定义与功能

  1. 定义:SpringBoot Starter是一组预先打包好的Maven依赖组合,提供了开发某一类功能所需要的所有依赖。这些Starter将常用的功能场景抽取出来,做成了一系列场景启动器,这些启动器帮助开发者导入了实现各个功能所需要依赖的全部组件。
  2. 功能
    • 自动导入相关组件:开发者只需在项目中引入对应的Starter,Spring Boot就会自动导入实现该功能所需的所有依赖。
    • 自动配置:Starter还包含了自动配置的功能,开发者只需通过配置文件进行少量配置,即可使用相应的功能。

二、命名规范与分类

  1. 命名规范
    • 官方Starter:通常命名为“spring-boot-starter-{name}”,例如spring-boot-starter-web。
    • 自定义Starter:遵循“{name}-spring-boot-starter”的格式,例如mybatis-spring-boot-starter。
  2. 分类
    • 官方Starter:Spring Boot官方提供的,用于快速构建和配置特定类型应用程序的Starter。
    • 第三方Starter:由社区或第三方组织提供的,用于扩展Spring Boot功能的Starter。

三、常用Starter示例

  1. spring-boot-starter-web
    • 功能:用于构建Web应用程序,提供了Spring MVC和嵌入式Tomcat支持。
    • 引入方式:在pom.xml中添加对应的依赖。
    • 配置:通过application.properties或application.yml文件进行配置。
  2. spring-boot-starter-data-jpa
    • 功能:用于与数据库交互,提供了JPA支持,并集成了Hibernate。
    • 引入方式:同样在pom.xml中添加对应的依赖。
    • 配置:需要配置数据库连接信息、JPA方言等。
  3. spring-boot-starter-security
    • 功能:用于实现用户认证和授权功能,集成了Spring Security。
    • 引入与配置方式:与上述Starter类似。

四、自定义Starter

  1. 定义:自定义Starter是指开发者根据自己的需求,将常用的依赖和配置打包为一个Starter,以便在多个项目中进行复用和共享。
  2. 创建流程
    • 创建一个新的Maven项目,并添加必要的依赖。
    • 编写自定义的业务类和自动配置类。
    • 在资源目录下创建spring.factories文件,并指定自动配置类的路径。
    • 将项目打包为jar文件,并发布到Maven仓库。
  3. 使用方式:在其他Spring Boot项目中,通过引入自定义Starter的依赖,并使用配置文件进行必要的配置,即可使用自定义Starter提供的功能。

五、注意事项

  1. 选择合适的Starter:根据项目需求选择合适的Starter,避免引入不必要的依赖和配置。
  2. 了解默认配置:在使用Starter时,要了解其默认包含的库和配置,以便根据需要进行调整和优化。
  3. 自定义配置:如果默认配置不满足需求,可以通过配置文件进行自定义配置。

综上所述,SpringBoot Starter是一种用于简化依赖管理和配置的方式,它通过将常用的功能场景抽取出来并打包为一系列场景启动器,帮助开发者快速构建和配置特定类型的应用程序。

依赖管理

在基于Spring Boot的Maven项目中,通常不需要指定starter的版本,原因在于Spring Boot的依赖管理机制。具体来说,这种机制的核心在于spring-boot-starter-parentspring-boot-dependencies

  1. spring-boot-starter-parent:这是一个特殊的父POM(Project Object Model),它为Spring Boot项目提供了默认的依赖管理配置。当一个Spring Boot项目继承了spring-boot-starter-parent时,它会自动管理所有依赖的版本号,包括starter依赖。因此,在添加starter依赖时,可以省略版本号。
  2. spring-boot-dependencies:这个模块在spring-boot-starter-parent中定义了一个dependencyManagement元素,用于集中管理所有需要的jar包及其版本号。spring-boot-dependencies包含了Spring Boot项目常用的依赖和它们的版本号。当在项目的pom.xml文件中添加一个starter依赖时,Maven会自动查找并使用在spring-boot-dependencies中定义的版本号。

这种机制的好处在于:

  • 可以在一个地方统一管理所有的依赖版本号,避免了在多个地方重复指定版本号的繁琐操作。
  • 降低了因版本号不一致而导致的问题。
  • 减少了因版本不兼容导致的问题。

同时,虽然Spring Boot提供了默认的依赖管理配置,但开发者仍然可以通过在子POM中明确指定依赖的版本号来覆盖默认的版本号。这样可以确保项目的编译和运行时一致性,特别是当需要使用特定版本的依赖时。

综上所述,基于Spring Boot的Maven项目不需要指定starter的版本号,是因为Spring Boot通过spring-boot-starter-parentspring-boot-dependencies提供了统一的依赖管理配置,简化了依赖管理过程。

修改依赖的默认版本

通过依赖的<version>标签直接指定

xml
<!-- mariadb驱动依赖 -->
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>3.4.0</version>
    <scope>runtime</scope>
</dependency>

通过 properties 属性修改

xml
<properties>
    <mariadb.version>3.4.0</mariadb.version>
</properties>

自动配置

Spring Boot自动配置能够根据应用程序所使用的框架、库或环境条件,自动配置相应的功能和组件。例如,当应用程序添加了数据库相关的依赖时,Spring Boot可以自动配置数据库连接池、事务管理等组件,无需手动配置。

自定义属性

示例的详细用法请参考https://gitee.com/dexterleslie/demonstration/tree/master/demo-spring-boot/demo-spring-boot-configurationproperties

借助@ConfigurationProperties定义java对应的自定义属性bean,其中通过@Validated + @NotEmpty + @NotNull启用属性值验证特性

java
// 表示此自定义属性启用验证
// https://reflectoring.io/validate-spring-boot-configuration-parameters-at-startup/
@Validated
// 默认读取application.properties文件中自定义属性
// 自定义属性以spring.future.common开头
@ConfigurationProperties(prefix = "spring.future.common")
@Data
public class MyProperties {
    // 表示application.properties中要配置有值
    @NotEmpty
    // 表示application.properties中需要存在此配置,但可以为空字符串
    // 如果不存在应用不能启动
    @NotNull
    private String p1;

    @NotNull
    private List<String> p2;

    private List<ClientProperty> clients;
}
java
@Data
public class ClientProperty {
    private String id;
    private String name;
}

application.properties配置自定义属性

properties
# 自定义属性
spring.future.common.p1=v1
spring.future.common.p2[0]=v21
spring.future.common.p2[1]=v22

spring.future.common.clients[0].id=id1
spring.future.common.clients[0].name=name1
spring.future.common.clients[1].id=id2
spring.future.common.clients[1].name=name2

借助@EnableConfigurationProperties启用MyProperties加载application.properties中的自定义属性

java
@Configuration
// 启用MyProperties加载application.properties中的自定义属性值并注入MyProperties实例到spring容器中
@EnableConfigurationProperties(MyProperties.class)
public class MyConfig {
}

使用application.properties中配置的属性值

java
@RestController
@RequestMapping("/api/v1")
public class ApiController {

    // 注入并使用自定义属性
    @Resource
    MyProperties myProperties;

    @GetMapping("test1")
    ObjectResponse<String> test1() {
        return ResponseUtils.successObject("p1=" + this.myProperties.getP1() + ",p2=" + this.myProperties.getP2());
    }
}

Profile 环境切换

详细用法请参考示例https://gitee.com/dexterleslie/demonstration/tree/master/demo-spring-boot/demo-spring-boot-profile

使用 @Profile 注解指定特定的 Profile 环境才创建 bean

java
package com.future.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
public class MyDatasourceConfig {
    // active profile为dev或default时,创建该bean
    @Profile({"dev", "default"})
    @Bean
    public MyDatasource myDevDatasource() {
        return new MyDatasource("dev-ds");
    }

    @Profile("test")
    @Bean
    public MyDatasource myTestDatasource() {
        return new MyDatasource("test-ds");
    }

    @Profile("prod")
    @Bean
    public MyDatasource myProdDatasource() {
        return new MyDatasource("prod-ds");
    }
}

properties 文件配置各个 Profile 配置

application-dev.properties 内容如下:

properties
my.p2=dev2

application-test.properties 内容如下:

properties
my.p2=test2

application-pod.properties 内容如下:

properties
my.p2=prod2

yaml 文件配置各个 Profile 配置

application.yaml 内容如下:

yaml
---
# 开发环境profile
my:
  p1: dev1
spring:
  profiles: dev

---
# 生产环境profile
my:
  p1: prod1
spring:
  profiles: prod

---
# 测试环境profile
my:
  p1: test1
spring:
  profiles: test

切换 Profile 方法

方法1:在单元测试时使用 @ActiveProfiles("test") 切换 Profile

java
@SpringBootTest(classes = Application.class)
@ActiveProfiles("test")
public class ApplicationTests {

方法2:在 application.properties 配置中使用 spring.profiles.active=dev 切换 Profile

properties
spring.profiles.active=dev

方法3:在 java 命令行中切换 Profile

bash
java -jar myapp.jar --spring.profiles.active=dev

方法4:编程式切换 Profile

https://stackoverflow.com/questions/31267274/spring-boot-programmatically-setting-profiles

java
// https://stackoverflow.com/questions/31267274/spring-boot-programmatically-setting-profiles
SpringApplication application = new SpringApplication(Application.class);
application.setAdditionalProfiles(springProfile);
context = application.run();

自定义 Starter

详细用法请参考https://gitee.com/dexterleslie/demonstration/tree/master/demo-spring-boot/demo-spring-boot-starter

自定义 Starter 插件

创建普通的 SpringBoot 项目

通过 @ConfigurationProperties(prefix = "com.future.demo.test") 自定义插件支持的配置属性

java
package com.future.demo.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;
import java.util.Map;

@Data
@ConfigurationProperties(prefix = "com.future.demo.test")
public class TestProperties {
    private String prop1;
    private int prop2;
    private List<String> prop3;
    private Map<String, String> prop4;
    private NestedTestProperties nested;

    @Data
    public static class NestedTestProperties {
        private String prop1;
        private int prop2;
    }
}

定义 service、controller 等组件

java
package com.future.demo.service;

import com.future.demo.properties.TestProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TestService {
    @Autowired
    TestProperties testProperties;

    public TestProperties getTestProperties() {
        return testProperties;
    }
}

package com.future.demo.controller;

import com.future.common.http.ObjectResponse;
import com.future.demo.properties.TestProperties;
import com.future.demo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @Autowired
    private TestService testService;

    @GetMapping("/")
    public ObjectResponse<TestProperties> index() {
        ObjectResponse<TestProperties> response = new ObjectResponse<>();
        response.setData(testService.getTestProperties());
        return response;
    }
}

插件自动配置类 DemoPluginAutoConfiguration

java
package com.future.demo.config;

import com.future.demo.properties.TestProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

// 当 TestProperties 类存在时,加载该配置类
@ConditionalOnClass(value = TestProperties.class)
// 启用自定义属性
@EnableConfigurationProperties(TestProperties.class)
public class DemoPluginAutoConfiguration {
}

配置spring自动扫描入口并自动配置插件的/src/main/resources/META-INF/spring.factories

properties
# 引入依赖后spring会自动扫描这个入口自动配置插件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.future.demo.config.DemoPluginAutoConfiguration

编译并安装插件到本地 maven 中

bash
./mvnw install

引用自定义 Starter 插件

maven 依赖中引用插件

xml
<!-- 引用自定义插件 -->
<dependency>
    <groupId>com.future.demo</groupId>
    <artifactId>demo-plugin-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

测试引用的插件

java
package com.future.demo;

import com.future.demo.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class})
@AutoConfigureMockMvc
public class ApplicationTests {
    @Autowired
    MockMvc mockMvc;
    @Autowired
    TestService testService;

    @Test
    public void contextLoads() throws Exception {
        this.mockMvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(content().string("{\"errorCode\":0,\"errorMessage\":null,\"data\":{\"prop1\":\"astring1\",\"prop2\":18080,\"prop3\":[\"av1\",\"av2\"],\"prop4\":{\"k1\":\"avv1\",\"k2\":\"avv2\"},\"nested\":{\"prop1\":\"anv1x\",\"prop2\":18090}}}"));

        Assertions.assertEquals("astring1", this.testService.getTestProperties().getProp1());
        Assertions.assertEquals(2, this.testService.getTestProperties().getProp3().size());
        Assertions.assertEquals("avv1", this.testService.getTestProperties().getProp4().get("k1"));
        Assertions.assertEquals("anv1x", this.testService.getTestProperties().getNested().getProp1());
        Assertions.assertEquals(18090, this.testService.getTestProperties().getNested().getProp2());
    }
}

生命周期

示例详细用法请参考https://gitee.com/dexterleslie/demonstration/tree/master/demo-spring-boot/demo-spring-boot-lifecycle

SpringApplicationRunListener(全阶段)

SpringApplicationRunListener是Spring Boot框架中的一个重要接口,它主要用于监听Spring Boot应用启动过程中的不同阶段。通过实现这个接口,开发者可以在应用启动的过程中插入自定义的逻辑,如日志记录、性能监控或额外的资源加载等。以下是对SpringApplicationRunListener的详细解析:

一、接口定义与功能

SpringApplicationRunListener接口定义了一系列回调方法,这些方法在应用启动的不同阶段被调用。这些阶段包括:

  1. 准备环境(EnvironmentPrepared):在读取应用程序配置、解析命令行参数后,准备运行环境。此时,可以访问和修改应用程序的环境属性。
  2. 准备上下文(ContextPrepared):在应用上下文被创建并准备好但尚未刷新时。此时,可以访问和修改应用程序上下文的配置。
  3. 上下文加载完成(ContextLoaded):在应用上下文加载完成但还未启动时。此时,可以执行一些在上下文刷新之前的自定义逻辑。
  4. 上下文启动(Started):应用上下文刷新并启动。此时,可以执行一些在所有Bean初始化之后的操作。
  5. 运行完成(Running/Ready):整个应用完全启动并准备处理请求。此时,可以执行一些应用程序启动后的最终检查或操作。注意,在Spring Boot 2.6及以上版本中,running方法被ready方法替换,以更准确地表示应用已经完全准备好处理外部请求的状态。
  6. 启动失败(Failed):应用在启动过程中发生错误或异常。此时,可以处理启动失败的情况,如记录错误日志、发送通知等。

二、实现与注册

要实现SpringApplicationRunListener接口,开发者需要完成以下步骤:

  1. 创建实现类:创建一个类并实现SpringApplicationRunListener接口,同时重写其定义的回调方法。在方法中插入自定义的逻辑。
  2. 注册监听器:要使Spring Boot能够发现并使用自定义的监听器,需要在META-INF/spring.factories文件中进行注册。通常,Spring Boot会自动加载该文件中的配置,并将注册的监听器添加到应用启动流程中。

三、使用示例

以下是一个简单的SpringApplicationRunListener实现示例:

java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import java.time.Duration;
 
public class CustomSpringApplicationRunListener implements SpringApplicationRunListener {
 
    public CustomSpringApplicationRunListener(SpringApplication application, String[] args) {
        // 构造函数中可以访问SpringApplication实例和启动参数
    }
 
    @Override
    public void starting() {
        System.out.println("应用正在启动...");
    }
 
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("环境已经准备好...");
    }
 
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("上下文已准备...");
    }
 
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("上下文已加载...");
    }
 
    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("应用已启动! 启动耗时: " + timeTaken.toMillis() + " 毫秒");
    }
 
    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("应用已准备就绪! 启动耗时: " + timeTaken.toMillis() + " 毫秒");
    }
 
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("应用启动失败: " + exception.getMessage());
    }
}

然后,在META-INF/spring.factories文件中注册该监听器:

org.springframework.boot.SpringApplicationRunListener=\
com.example.CustomSpringApplicationRunListener

四、注意事项

  1. 版本兼容性:不同版本的Spring Boot可能对SpringApplicationRunListener的回调方法有所调整,因此在使用时需要确保与所使用Spring Boot版本的兼容性。
  2. 性能影响:在应用启动过程中插入自定义逻辑可能会对启动性能产生影响,因此需要根据实际需求谨慎使用。
  3. 错误处理:在实现自定义逻辑时,需要注意异常处理,以避免因异常导致应用启动失败。

综上所述,SpringApplicationRunListener为开发者提供了在应用启动过程中插入自定义逻辑的灵活机制,有助于实现更丰富的应用启动行为和监控需求。

ApplicationListener(全阶段)

ApplicationListener是Spring框架中的一个重要接口,它允许开发者监听并处理应用程序中的事件。以下是关于ApplicationListener的详细解析:

一、接口定义与功能

ApplicationListener接口定义了一个onApplicationEvent方法,该方法在监听到事件发布后被自动调用。事件发布者并不需要知道哪些监听器会监听该事件,也不需要关心监听器如何实现事件处理逻辑。这种机制实现了发布者与监听者之间的解耦,提高了系统的可扩展性和可维护性。

二、事件机制的主要组成部分

Spring框架中的事件机制主要包括以下几个组成部分:

  1. 事件(Event):事件是应用程序中可能发生的事情,它通常是一个继承自ApplicationEvent的类。开发者可以定义自己的事件类,以便在应用程序中传递关键信息。
  2. 事件发布者(ApplicationEventPublisher):事件发布者负责发布事件。在Spring中,ApplicationEventPublisher接口是事件发布者的标准接口,它定义了发布事件的方法publishEvent(Event event)。Spring中的容器,如ApplicationContext,实现了这个接口,允许在应用程序中发布事件。
  3. 事件监听器(ApplicationListener):事件监听器负责监听并处理特定类型的事件。ApplicationListener接口是事件监听器的标准接口,它定义了用于处理事件的方法onApplicationEvent(Event event)。开发者可以实现这个接口,以便在事件发生时执行自定义的逻辑。
  4. 事件广播器(ApplicationEventMulticaster):事件广播器是框架内部的组件,负责将事件分发给所有注册的监听器。Spring提供了多个事件广播器的实现,其中SimpleApplicationEventMulticaster是一个简单的单线程实现。

三、使用方法

要使用ApplicationListener,开发者需要实现该接口,并将实现类注册到Spring容器中。当容器中有相应的事件触发时,Spring会自动调用监听器的onApplicationEvent方法。

四、自定义事件与监听器

开发者可以自定义事件和监听器,以满足特定的业务需求。自定义事件需要继承ApplicationEvent类,并在构造函数中传递事件源。自定义监听器需要实现ApplicationListener接口,并在onApplicationEvent方法中编写事件处理逻辑。

五、内置事件

Spring框架提供了一些内置事件,这些事件在特定的时间点被自动发布。例如:

  • ContextRefreshedEvent:当ApplicationContext被初始化或刷新时发布。
  • ContextClosedEvent:当ApplicationContext被关闭时发布。
  • RequestHandledEvent:这是一个web-specific事件,告诉所有bean HTTP请求已经被服务。

六、应用场景

ApplicationListener在Spring框架中有着广泛的应用场景,例如:

  • 通知服务:在完成某项操作后发布事件,由专门的服务监听并执行相应的动作,如发送邮件或短信通知。
  • 日志记录:发布日志相关的事件,可以被不同的监听器接收以进行日志处理。
  • 异步处理:在某个操作完成后发布事件,由另一个线程或服务来处理后续逻辑,如文件上传后的处理等。

七、注意事项

  1. 避免循环依赖:在事件处理过程中,避免创建与事件发布者或监听器本身存在循环依赖的Bean。
  2. 性能影响:由于事件监听器在事件发生时被自动调用,因此可能会对应用的性能产生影响。因此,在使用时需要谨慎考虑是否需要在事件发生时执行这些操作。
  3. 异常处理:在实现事件监听器时,需要注意异常处理,以避免因异常导致应用崩溃或不稳定。

综上所述,ApplicationListener是Spring框架中一个非常有用的接口,它允许开发者以解耦的方式监听并处理应用程序中的事件。通过合理使用ApplicationListener,可以提高系统的可扩展性和可维护性,并满足各种业务需求。

BootstrapRegistryInitializer(引导初始化阶段)

BootstrapRegistryInitializer是Spring Boot框架中的一个重要组件,它主要用于在应用启动阶段初始化和注册一些在ApplicationContext准备好之前就需要被创建和共享的对象。以下是对BootstrapRegistryInitializer的详细解析:

一、接口定义与功能

BootstrapRegistryInitializer接口定义了一个initialize方法,该方法接收一个BootstrapRegistry类型的参数。BootstrapRegistry是一个简单的对象注册表,它在启动和环境后处理期间都可用,直到ApplicationContext准备好为止。这个注册表可以用于注册那些可能创建成本较高或在ApplicationContext可用之前就需要被共享的实例。

二、实现与加载

  1. 实现接口

    BootstrapRegistryInitializer接口的实现类需要重写initialize方法,并在该方法中执行必要的初始化和注册操作。

  2. 加载机制

    Spring Boot通过SpringFactoriesLoader机制来加载实现了BootstrapRegistryInitializer接口的类。这些类的全限定名会被配置在META-INF/spring.factories文件中,并且与org.springframework.boot.BootstrapRegistryInitializer这个key相关联。

    例如,在Spring Cloud Config中,就通过BootstrapRegistryInitializer将配置中心的相关信息注册到了Spring容器中。其对应的实现类是ConfigClientRetryBootstrapper,并且这个实现类会在spring-cloud-config-client这个jar包的META-INF/spring.factories文件中被配置。

三、使用场景与示例

BootstrapRegistryInitializer通常用于需要在ApplicationContext准备好之前就被创建和共享的场景。例如,在Spring Cloud Config中,客户端需要向配置中心(Config Server)发送请求来获取应用程序的配置信息。这些配置信息需要在ApplicationContext创建之前就被加载和解析,因此就可以通过实现BootstrapRegistryInitializer接口来完成这个任务。

四、注意事项

  1. 版本兼容性

    不同版本的Spring Boot可能会对BootstrapRegistryInitializer的加载和初始化机制有所不同,因此在使用时需要确保与所使用Spring Boot版本的兼容性。

  2. 性能影响

    由于BootstrapRegistryInitializer是在ApplicationContext准备好之前执行的,因此它可能会对应用的启动性能产生影响。因此,在使用时需要谨慎考虑是否需要在启动阶段执行这些操作。

  3. 错误处理

    在实现BootstrapRegistryInitializer时,需要注意异常处理,以避免因异常导致应用启动失败。

五、总结

BootstrapRegistryInitializer是Spring Boot框架中的一个重要组件,它允许开发者在应用启动阶段初始化和注册一些需要在ApplicationContext准备好之前就被创建和共享的对象。通过实现这个接口,开发者可以在应用启动的过程中插入自定义的逻辑,以满足特定的需求。同时,也需要注意版本兼容性、性能影响和错误处理等方面的问题。

ApplicationContextInitializer(IOC 容器初始化阶段)

ApplicationContextInitializer是Spring框架中的一个扩展接口,它在应用程序上下文(ApplicationContext)创建之前提供了自定义初始化的能力。通过实现该接口,开发者可以在应用程序上下文启动之前执行一些额外的配置或准备工作。以下是对ApplicationContextInitializer的详细解析:

一、接口定义与功能

ApplicationContextInitializer接口定义了一个initialize方法,该方法接收一个泛型参数C extends ConfigurableApplicationContext,表示正在创建的应用程序上下文。在该方法中,开发者可以对应用程序上下文进行各种自定义操作,例如添加属性源、注册Bean定义、设置环境变量等。

二、应用场景

ApplicationContextInitializer通常用于以下场景:

  1. 动态加载配置:在应用程序上下文创建之前加载一些动态的配置,例如从外部配置文件中读取配置信息并注入到Spring的环境中。
  2. 执行额外的初始化逻辑:如果有一些需要在应用程序上下文启动之前执行的初始化逻辑,例如初始化数据库连接池或启动一些后台任务,可以通过实现ApplicationContextInitializer来实现这些逻辑。

三、实现与注册

  1. 实现接口

    创建一个类并实现ApplicationContextInitializer接口,同时重写initialize方法。在方法中执行所需的初始化逻辑。

  2. 注册ApplicationContextInitializer

    要使Spring能够发现并使用自定义的ApplicationContextInitializer,可以通过以下三种方式进行注册:

    • 在spring.factories文件中配置:在 resources/META-INF/spring.factories 文件中添加配置,指定ApplicationContextInitializer的实现类。例如:

      org.springframework.context.ApplicationContextInitializer=com.example.demo.CustomApplicationContextInitializer
    • 代码注册:在创建SpringApplication实例后,通过调用 addInitializers 方法将自定义的ApplicationContextInitializer添加到SpringApplication中。例如:

      java
      SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
      springApplication.addInitializers(new CustomApplicationContextInitializer());
      springApplication.run();
    • 配置文件注册:在 application.properties 或 application.yml 配置文件中添加 context.initializer.classes 属性,指定ApplicationContextInitializer的实现类。例如:

      properties
      context.initializer.classes=com.example.demo.CustomApplicationContextInitializer

四、执行顺序

ApplicationContextInitializer的执行顺序可以通过实现Ordered接口或使用@Order注解来指定。如果没有指定顺序,则按照默认的顺序执行。

五、注意事项

  1. 避免循环依赖:在初始化过程中,避免创建与ApplicationContext本身存在循环依赖的Bean。
  2. 性能影响:由于ApplicationContextInitializer在ApplicationContext创建之前执行,因此可能会对应用的启动性能产生影响。因此,在使用时需要谨慎考虑是否需要在启动阶段执行这些操作。
  3. 错误处理:在实现ApplicationContextInitializer时,需要注意异常处理,以避免因异常导致应用启动失败。

六、示例

以下是一个简单的ApplicationContextInitializer实现示例:

java
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
 
import java.util.HashMap;
import java.util.Map;
 
public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
 
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 自定义属性资源
        Map<String, Object> map = new HashMap<>();
        map.put("customProperty", "自定义属性");
 
        // 通过自动配置上下文获取环境对象
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
 
        // 添加自定义属性源到环境对象中
        environment.getPropertySources().addLast(new MapPropertySource("mapPropertySource", map));
    }
}

通过上述方式,开发者可以在Spring应用程序启动之前执行自定义的初始化逻辑,以满足特定的需求。

ApplicationRunner(Spring 应用就绪阶段)

ApplicationRunner是Spring Boot框架中的一个接口,它允许开发者在Spring Boot应用程序启动后执行特定的任务或逻辑。以下是关于ApplicationRunner的详细解析:

一、接口定义与功能

ApplicationRunner接口定义了一个run方法,该方法在Spring Boot应用程序启动完成后被调用。开发者可以在这个方法中编写希望在应用程序启动后执行的代码逻辑,如加载数据、调用外部服务或执行其他业务逻辑。

二、使用方法

要使用ApplicationRunner,开发者需要创建一个实现了ApplicationRunner接口的类,并实现其run方法。然后,将这个类注册为Spring的组件(通常是通过在类上添加@Component注解)。这样,当Spring Boot应用程序启动时,Spring会自动调用这个类的run方法。

三、参数与访问启动参数

run方法接受一个ApplicationArguments类型的参数,该参数提供了对启动参数的访问。通过ApplicationArguments,开发者可以获取命令行参数、选项和非选项参数等信息,从而更灵活地配置和初始化应用程序。

四、应用场景

ApplicationRunner在Spring Boot应用程序中有多种应用场景,包括但不限于:

  1. 服务启动后数据初始化:在应用启动时加载初始化数据,如将初始数据加载到数据库、从文件读取数据、缓存热点数据等。
  2. 应用启动时加载配置信息:在某些情况下,应用可能需要在启动时加载外部配置信息或数据库中的参数到内存中进行缓存。
  3. 启动时验证环境配置:在应用启动时验证环境配置的正确性,如验证许可证的有效性、检查系统环境变量等。
  4. 启动定时任务:在应用启动时重新激活或启动定时任务。

五、执行顺序与多个ApplicationRunner

如果应用程序中有多个实现了ApplicationRunner接口的类,并且这些类需要在特定的顺序下执行,开发者可以使用@Order注解来指定执行顺序。@Order注解的值越小,表示优先级越高,即越先执行。

六、注意事项

  1. 异常处理:在实现ApplicationRunner的run方法时,需要注意异常处理,以避免因异常导致应用崩溃或不稳定。
  2. 性能影响:由于ApplicationRunner在应用程序启动时执行,因此可能会对启动性能产生影响。开发者需要谨慎考虑在run方法中执行的操作是否必要,并尽量优化这些操作的性能。
  3. 避免循环依赖:在实现ApplicationRunner时,需要避免与Spring容器中的其他Bean产生循环依赖。

综上所述,ApplicationRunner是Spring Boot框架中一个非常有用的接口,它允许开发者在应用程序启动后执行特定的任务或逻辑。通过合理使用ApplicationRunner,开发者可以更灵活地配置和初始化应用程序,并满足各种业务需求。

CommandLineRunner(Spring 应用就绪阶段)

CommandLineRunner是Spring Boot框架中的一个重要接口,它允许开发者在Spring Boot应用程序启动后执行特定的代码逻辑。以下是对CommandLineRunner的详细解释:

一、接口定义与功能

CommandLineRunner接口定义了一个run方法,该方法在Spring Boot应用程序启动完成后被自动调用。通过实现CommandLineRunner接口,开发者可以定义一些需要在应用程序启动后执行的初始化操作,例如加载初始化数据、启动后打印应用信息、启动异步任务等。

二、使用方法

要使用CommandLineRunner,开发者需要完成以下步骤:

  1. 创建一个实现CommandLineRunner接口的类,并实现其run方法。
  2. run方法中编写需要在应用程序启动后执行的代码逻辑。
  3. 将这个类注册为Spring的组件,通常是通过在类上添加@Component注解。

这样,当Spring Boot应用程序启动时,Spring会自动调用这个类的run方法。

三、参数与命令行参数

run方法接受一个字符串数组参数,这个数组包含了应用程序启动时传递的命令行参数。这为开发者提供了一种在应用程序启动时动态配置或执行不同逻辑的机会。例如,可以根据命令行参数的不同来加载不同的配置文件或执行不同的初始化操作。

四、应用场景

CommandLineRunner在Spring Boot应用程序中有多种应用场景,包括但不限于:

  1. 数据初始化:在应用程序启动后加载初始化数据,如从数据库中加载配置信息或初始化一些全局变量。
  2. 应用信息打印:在应用程序启动后打印一些有用的信息,如应用程序的版本号、内存使用情况等,以帮助开发者了解应用程序的运行状态和性能。
  3. 异步任务启动:在应用程序启动后启动一些异步任务,如发送电子邮件或进行一些批处理操作。
  4. 参数校验:在实现CommandLineRunner接口时,可以进行一些参数校验,以确保应用程序在运行之前满足一些必要的条件或参数要求,从而提高应用程序的健壮性和安全性。

五、与ApplicationRunner的区别

CommandLineRunner与ApplicationRunner都是Spring Boot中用于在应用程序启动后执行特定逻辑的接口。它们的主要区别在于run方法的参数不同:

  • CommandLineRunner的run方法接受一个字符串数组参数,该参数包含了应用程序启动时传递的命令行参数。
  • ApplicationRunner的run方法则接受一个ApplicationArguments对象作为参数,该对象提供了对启动参数的更高级别的访问,包括选项和非选项参数等。

六、注意事项

  1. 异常处理:在实现CommandLineRunner的run方法时,需要注意异常处理,以避免因异常导致应用崩溃或不稳定。
  2. 性能影响:由于CommandLineRunner在应用程序启动时执行,因此可能会对启动性能产生影响。开发者需要谨慎考虑在run方法中执行的操作是否必要,并尽量优化这些操作的性能。
  3. 执行顺序:如果有多个实现了CommandLineRunner接口的类,并且这些类需要在特定的顺序下执行,开发者可以使用@Order注解来指定执行顺序。

综上所述,CommandLineRunner是Spring Boot框架中一个非常有用的接口,它允许开发者在应用程序启动后执行特定的代码逻辑。通过合理使用CommandLineRunner,开发者可以更灵活地配置和初始化应用程序,并满足各种业务需求。

application.properties 中配置获取随机数

https://dev.to/mxglt/generate-random-values-in-your-properties-spring-boot-4ppf

properties
leaf.snowflake.port=${random.int%1000000000}
  • leaf.snowflake.port 会随机生成一个整数并求余
  • 此配置由 RandomValuePropertySource 解析