Skip to content

Spring Boot

Spring Boot有什么特点?

Spring Boot 是Spring 框架的一个扩展,遵循约定优于配置的设计理念,核心价值在于其能够简化了Spring框架中所需的大量且繁琐的配置文件,并提供大量开发组件,显著降低Spring 应用程序的开发复杂度,让开发者可以专注于业务逻辑而不是基础设施配置。它不仅适用于小型项目,也能很好地适应大型企业级应用的需求。随着微服务架构的流行,Spring Boot 成为了构建现代 Java 应用的首选框架之一。

Spring Boot的特点如下:

  1. 快速入门与简化配置

    • 自动配置:根据项目依赖自动配置 Spring 应用,减少了大量的 XML 或 Java 配置。

    • 起步依赖(Starters):提供了预定义的依赖集合,例如 spring-boot-starter-web,可以帮助开发者更方便地引入常用功能模块。

  2. 内嵌服务器支持

    • 内置了 Tomcat, Jetty, 或 Undertow 等 Web 服务器,无需单独部署到外部容器中,可以直接通过命令行启动应用。
  3. 开箱即用的安全性

    • 提供了简单易用的安全框架集成,如 Spring Security,并且可以通过少量配置实现基本的身份验证和授权功能。
  4. 微服务支持

    • 支持构建微服务架构,包括服务发现、配置管理、API 网关等功能,通常结合 Spring Cloud 使用。
  5. 监控与管理

    • 提供了 Actuator 模块来监控和管理应用程序,包含健康检查、度量指标收集、环境信息暴露等功能。
  6. 外部化配置

    • 支持从多种来源加载配置属性,如文件系统、环境变量、命令行参数等,便于不同环境下的灵活配置。
  7. CLI 工具

    • 提供了一个命令行接口 (CLI),允许用户编写 Groovy 脚本来快速测试或原型开发 Spring Boot 应用。
  8. 无代码生成和XML配置

    • 尽量减少需要手写的样板代码和 XML 配置,鼓励使用注解驱动的方式来定义组件和服务。
  9. DevTools 开发工具

    • 包含了一套开发人员工具包 DevTools,提供了热部署、远程调试等功能,提升了开发效率。
  10. 云原生特性

    • 设计之初就考虑到了云计算环境下的需求,如 Docker 容器化友好,Kubernetes 集成良好,支持分布式跟踪等。
  11. 社区活跃和支持

    • 拥有庞大的开源社区和丰富的文档资源,确保了长期的技术支持和持续更新。
  12. 强大的生态系统

    • 除了核心功能外,还拥有众多扩展库和第三方集成,几乎涵盖了所有常见的企业级应用场景和技术领域。

SpringBoot 自动配置原理?

SpringBoot自动配置是SpringBoot框架的一个重要特性,是**在 SPI(SPI ,全称为 Service Provider Interface,是一种服务发现机制)**基础上依赖于注解、配置文件、条件注解等多个方面来实现,它根据当前的类路径依赖、配置文件和运行环境自动注册所需的Spring Bean。

一、核心注解与自动配置启动

  1. @EnableAutoConfiguration注解

    • 该注解是SpringBoot自动配置的关键,用于启用自动配置功能。它通常与@SpringBootApplication注解一起使用。

    • @EnableAutoConfiguration注解通过@Import注解导入了AutoConfigurationImportSelector类,这是自动配置的核心处理器,这个类负责扫描并加载自动配置类。AutoConfigurationImportSelector类的作用是从配置文件中(通常是 spring.factories)读取所有的自动配置类,并将它们导入到应用上下文中。

  2. spring.factories文件

    • 这个文件位于jar包下的META-INF目录中,包含了可以进行自动配置的类。

    • Spring Boot会扫描这个文件,并根据其中的配置来实例化自动配置类。

二、条件注解与配置类

  1. 条件注解

    • Spring Boot的自动配置类中使用了很多条件注解,如@ConditionalOnClass、@ConditionalOnProperty、@ConditionalOnMissingBean等。

    • 这些注解根据特定的条件来判断是否需要启用某个自动配置类。例如,@ConditionalOnClass注解会检查classpath中是否存在某个特定的类,如果存在,则启用相关的自动配置。

  2. 自动配置类

    • Spring Boot 的自动配置是通过自动配置类实现的。这些类通常位于 org.springframework.boot.autoconfigure 包下。

    • 自动配置类根据classpath的内容和定义的条件化逻辑来配置应用程序的各个组件

    • 自动配置类可能会创建beans、设置属性或者做一些初始化工作。

三、默认值与外部配置

  1. 默认值

    • 约定大于配置(Convention over Configuration)如果没有找到任何配置信息,Spring Boot会使用默认值来进行自动配置。
  2. 外部配置

    • Spring Boot允许使用properties或yaml文件来外部配置应用。

    • 这些配置可以与自动配置紧密结合,允许开发者覆盖自动配置的默认属性值。

四、Starter依赖

  1. Starter组件

    • 启动器是一种依赖关系管理的机制,它可以简化项目的依赖管理,同时自动配置了特定类型的应用程序。

    • Starter组件是可被加载在应用中的Maven依赖项。

  2. 功能集成

    • 通过引入适当的启动器,你可以一次性地引入一组相关的依赖和自动配置,从而快速搭建特定类型的应用程序,如Web 应用、数据访问应用等。

五、自动配置流程

  1. 检查自动配置功能是否开启:默认情况下,自动配置功能是开启的。
  2. 加载自动配置的元信息:通过AutoConfigurationMetadataLoader类加载spring.factories文件中的自动配置类信息。
  3. 获取候选配置类:根据项目的依赖和classpath内容,获取所有可能的自动配置类。
  4. 去重与排除:去除重复的配置类,并根据@SpringBootApplication注解中的exclude属性或@SpringBootExclude注解排除不需要的自动配置类。
  5. 过滤与排序:根据条件注解和自动配置类的优先级进行过滤和排序。
  6. 实例化与注册:将符合条件的自动配置类实例化,并将它们注册到Spring容器中。

六、自动配置的优势

  • **减少配置工作量,**通过自动配置,开发者无需手动编写大量的配置文件和Bean定义,从而减少了配置工作量。
  • **提高开发效率,**自动配置使得开发者可以更快地搭建起一个完整的项目,提高了开发效率。
  • **灵活可定制,**虽然SpringBoot提供了自动配置功能,但开发者仍然可以通过编写自定义的配置类和配置文件来覆盖默认配置,从而实现灵活可定制的项目需求。
  • 一致性:确保了最佳实践的一致应用,比如安全性和性能优化等方面。
  • 非侵入性:自动配置不会强制改变你的代码结构或编写方式,而是作为额外的支持来简化常见的任务,同时你可以随时选择关闭特定的自动配置或者完全绕过它,以实现更细粒度的控制。

SpringBoot 查看和禁用自动配置?

查看已应用的自动配置:可以通过启用调试日志级别或将 debug=true 添加到 application.properties 文件中,来获得详细的自动配置报告。

禁用特定自动配置:如果你不想使用某个自动配置类,可以在 application.properties 中通过 spring.autoconfigure.exclude 属性排除它。

properties
debug=true
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

SpringBoot 禁用某些自动配置特性?

禁用某些自动配置特性,可以使用 @EnableAutoConfiguration 或 @SpringBootApplication 注解的 exclude 属性来指明。

java
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

也可在application.properties配置文件中配置:

properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

SpringBoot 核心注解?

@SpringBootApplication 是SpringBoot 的核心注解,它是一个组合注解,由三个子注解组成。

  1. @SpringBootConfiguration

    • 它本身是一个特殊的 @Configuration 注解,而 @Configuration 注解又包含了 @Component 注解。

    • 这个注解标识了当前类是一个 Spring Boot 配置类,表明该类可以使用 Spring 的基于 Java 的配置方式,同时该类也是 Spring 容器中的一个组件。

    • 在这个配置类中,可以使用 @Bean 注解来定义和初始化由 Spring 容器管理的对象。

  2. @EnableAutoConfiguration

    • 这个注解用于启用 Spring Boot 的自动配置功能,自动装配核心功能的实现实际是通过 **AutoConfigurationImportSelector**类。

    • 它会自动扫描 @SpringBootApplication 注解所在类所在的包,并将该包及其子包下的所有组件加载到 Spring 的容器中。

    • 它还会从配置文件 META-INF/spring.factories 中加载所有可能用到的自动配置类,并根据条件装配规则(@Conditional)进行过滤,最终将满足条件的自动配置类加载到 Spring 容器中。

    • 开发者可以通过 @EnableAutoConfiguration 的 exclude 或 excludeName 属性来排除特定的自动配置类,以避免不必要的自动配置。

  3. @ComponentScan

    • 这个注解用于启用组件扫描功能。

    • 它会扫描当前包及其子包中的组件(如使用 @Component、@Service、@Repository、@Controller 等注解的类),并将这些组件注册为 Spring 容器中的 Bean。

    • 开发者可以通过 @ComponentScan 的 scanBasePackages 或 scanBasePackageClasses 属性来指定要扫描的包或类,从而覆盖默认的扫描行为。

自定义配置

@SpringBootApplication 提供了一套合理的默认行为,但你仍然可以通过额外的参数来自定义它的行为:

  • scanBasePackages scanBasePackageClasses:指定要扫描的基础包或类,以覆盖默认的组件扫描路径。
  • exclude excludeName:用于排除某些自动配置类,防止它们被加载。这对于不想使用某些默认配置时非常有用。

@SpringBootApplication注解功能

  1. 标记主类:将该类标记为 Spring Boot 应用程序的主类,Spring Boot 会从该类开始启动应用程序。
  2. 自动配置:启用 Spring Boot 的自动配置功能,根据项目的依赖和环境自动配置 Spring 应用程序,从而简化了项目的配置过程。
  3. 组件扫描:自动扫描当前包及其子包下的组件,并将其注册为 Spring 的 Bean,开发者无需手动配置 @ComponentScan。

注意事项

  1. 主类位置:@SpringBootApplication 注解所在类的包路径通常作为 Spring Boot 的基础包路径。因此,建议将主配置类放在项目的根包路径下,以便更好地管理项目的包结构和组件扫描路径。
  2. 自定义配置:虽然 @EnableAutoConfiguration 注解提供了强大的自动配置功能,但在某些情况下,可能需要手动配置一些组件或调整自动配置的默认行为。这时,可以通过在 application.properties 或 application.yml 配置文件中添加相应的配置信息来实现。
  3. 组件扫描:@ComponentScan 注解默认会扫描当前包及其子包下的所有组件。如果需要扫描其他包路径下的组件,可以通过在 @ComponentScan 注解中指定 scanBasePackages 或 scanBasePackageClasses 属性来实现。
  4. 排除自动配置:如果某些自动配置类与项目的需求不符,可以通过 @SpringBootApplication 的 exclude 或 excludeName 属性来排除它们。
java
@SpringBootApplication(
    scanBasePackages = "com.example",
    exclude = {DataSourceAutoConfiguration.class}
)
public class MyCustomApplication {
    // ...
}

SpringBoot 常用注解 ?

  • @SpringBootApplication:替代 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
  • @ImportAutoConfiguration:导入配置类,一般做测试的时候使用,正常优先使用@EnableAutoConfiguration
  • @SpringBootConfiguration:替代@Configuration
  • @ImportResource:将资源导入容器
  • @PropertySource :导入properties文件
  • @PropertySources:@PropertySource 的集合
  • @Role:bean角色定义为ROLE_APPLICATION(默认值)、ROLE_SUPPORT(辅助角色)、ROLE_INFRASTRUCTURE(后台角色,用户无感)
  • @Scope:指定bean的作用域,默认singleton,其它包括prototype、request、session、globalSession
  • @Lazy:使bean懒加载,取消bean预初始化。
  • @Primary:自动装配时当出现多个Bean 选者时,被注解为@Primary的Bean将作为首选者,否者将抛出异常。
  • @Profile:指定Bean在哪个环境下被激
  • @DependsOn:依赖的bean注册完成,才注册当前类,依赖bean不存在会报错。用来控制bean加载顺序
  • @PostConstruct:bean的属性都注入完毕后,执行注解标注的方式进行初始化工
  • @Autowired:默认按类型装配,如果我们想使用名称装配,可以结合@Qualifier注解一起使用。
  • @Lookup:根据方法返回的类型,去容器中捞出对
  • @Qualifier:申明bean名字,且可以按bean名字加载bea
  • @Required:检查bean的属性setXXX方法,要求属性砸死配置阶段必须已配置
  • @Description:添加bean的文字描
  • @EnableAspectConfiguration:启动AspectJ自动配
  • @EnableLoadTimeWeaving:启动类加载器动态增强功能,使用instrumentation实
  • @AutoConfigurationPackage:包含该注解的packag会被AutoConfigurationPackages注册
  • @AutoConfigureBefore:在指定配置类初始化前载
  • @AutoConfigureAfter:在指定配置类初始化后加
  • @AutoConfigureOrder:指定配置类初始化顺序,越小初始化越早
  • @ModelAttribute 注解可被应用在方法和方法参数上。
  • @EnableCaching,开启缓存配置,支持子类代理或者AspectJ增强
  • @CacheConfig,在一个类下,提供公共缓存配置
  • @Cacheable,放着方法和类上,缓存方法或类下所有方法的返回值
  • @CachePut,每次先执行方法,再将结果放入缓存
  • @CacheEvict,删除缓存
  • @Caching,可以配置@Cacheable、@CachePut、@CacheEvict
  • @EnableScheduling,开启定时任务功能
  • @Scheduled,按指定执行周期执行方法
  • @Schedules,包含多个@Scheduled,可同时运行多个周期配置
  • @EnableAsync,开启方法异步执行的能力,通过@Async或者自定义注解找到需要异步执行的方法。通过实现AsyncConfigurer接口的getAsyncExecutor()和getAsyncUncaughtExceptionHandler()方法自定义Executor和异常处理。
  • @Async,标记方法为异步线程中执行
  • @ConditionalXXX,当指定的条件都满足时,组件才被注册

SpringBoot 常见条件注解?

Spring Boot 的条件注解是其自动配置机制的核心组成部分,它们允许开发者根据特定条件来控制 Bean 的创建和配置类的加载。条件注解基于 Spring 框架中的 @Conditional 注解,它本身是一个元注解,可以用它来创建自定义的条件注解。通过合理运用内置条件注解并结合自定义条件注解,可以构建出高度适应不同环境和需求的应用程序。 Spring Boot 提供了一系列预定义的条件注解,用于简化常见的条件逻辑。

@ConditionalOnClass@ConditionalOnMissingClass

  • 检查指定的类是否存在于类路径中。

  • @ConditionalOnClass:只有当指定的类存在时才生效。例如,如果类路径中存在 Redis 客户端库,则自动配置 Redis 连接工厂。

  • @ConditionalOnMissingClass:只有当指定的类不存在时才生效。这可以用来确保某些配置仅在缺少特定依赖项时被应用。

java
@Configuration
@ConditionalOnClass(RedisConnectionFactory.class)
public class RedisAutoConfiguration {
    // 自动配置 Redis 相关 Bean...
}

@ConditionalOnBean@ConditionalOnMissingBean

  • 检查应用程序上下文中是否存在或不存在某个类型的 Bean。

  • @ConditionalOnBean:只有当上下文中已经存在指定类型的 Bean 时才创建新的 Bean 或执行配置。

  • @ConditionalOnMissingBean:只有当上下文中不存在指定类型的 Bean 时才创建新的 Bean 或执行配置。这对于避免重复配置非常有用。

java
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
    // 只有当上下文中不存在自定义的数据源时,才创建默认数据源。
    return new EmbeddedDatabaseBuilder().build();
}

@ConditionalOnProperty

  • 根据配置文件中的属性值来决定是否应用配置。

  • 参数

    • prefix:属性名的前缀。

    • name:具体的属性名称。

    • havingValue:期望的属性值(可选,默认为 true)。

    • matchIfMissing:如果属性不存在,则默认匹配(可选,默认为 false)。

java
@Configuration
@ConditionalOnProperty(name = "feature.toggle.enabled", havingValue = "true")
public class FeatureToggleConfig {
    // 配置需要启用的功能...
}

@ConditionalOnExpression

  • 使用 SpEL(Spring Expression Language)表达式来定义复杂的条件逻辑。
  • 当需要更精细地控制 Bean 创建条件时,比如结合多个条件或者进行数值比较等操作。
java
@Bean
@ConditionalOnExpression("${app.feature.enabled:true} && ${spring.profiles.active=='prod'}")
public MyService myService() {
    return new MyServiceImpl();
}

@ConditionalOnWebApplication@ConditionalOnNotWebApplication

  • 判断应用程序是否为 Web 应用。
  • 某些配置可能只适用于 Web 环境,而另一些则更适合非 Web 环境(如批处理任务)。这两个注解可以帮助区分这两种情况。
java
@Configuration
@ConditionalOnWebApplication
public class WebSecurityConfig {
    // Web 安全相关配置...
}

@ConditionalOnJava

  • 根据 Java 版本来决定是否应用配置。
  • 对于依赖于特定 Java API 或特性的组件,可以通过此注解确保它们仅在支持的 Java 版本上运行。

组合使用条件注解

java
@Service
@ConditionalOnClass(StripeClient.class)
@ConditionalOnProperty(name = "payment.stripe.enabled", havingValue = "true")
@ConditionalOnExpression("'${spring.profiles.active}' == 'prod' || '${spring.profiles.active}' == 'test'")
public class PaymentService {
    private final StripeClient stripeClient;

    public PaymentService(StripeClient stripeClient) {
        this.stripeClient = stripeClient;
    }

    // Service implementation...
}

条件注解的应用场景

  • 环境特定配置:根据不同的运行环境(如开发环境、测试环境、生产环境)来加载不同的配置类。
  • 依赖特定配置:根据项目中是否存在特定的依赖库来加载相应的配置类。
  • 属性特定配置:根据配置文件中特定的属性值来加载相应的配置类。
  • Bean特定配置:根据容器中是否存在特定的Bean来加载相应的配置类。

SpringBoot 创建使用自定义条件注解?

除了使用内置条件注解外,还可以通过实现 Condition 接口来自定义条件逻辑,并将其封装为新的注解。

  1. 实现 Condition 接口

    首先,创建一个类实现 Condition 接口,并重写 matches() 方法以定义具体的条件逻辑。

    java
    public class MyCustomCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // 自定义条件逻辑,例如检查环境变量或系统属性
            return System.getenv("MY_CUSTOM_ENV_VAR") != null;
        }
    }
  2. 定义自定义条件注解

    接下来,定义一个新的注解,并用 @Conditional 注解它,指定刚刚创建的条件类。

    java
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Conditional(MyCustomCondition.class)
    public @interface ConditionalOnMyCustomCondition {
    }
  3. 使用自定义条件注解

    最后,在配置类或方法上应用自定义条件注解。

    java
    @Configuration
    @ConditionalOnMyCustomCondition
    public class CustomFeatureConfig {
        // 配置内容...
    }

spring.factories文件的作用?

spring.factories 文件是 Spring Boot 自动化配置的核心之一,它位于 JAR 文件的 META-INF 目录下,全路径为 META-INF/spring.factories。这个文件的作用类似于一个注册表,定义了哪些类应该在应用程序启动时被自动发现并加载。它极大地简化了框架和库之间的集成过程,同时提供了强大的扩展能力。理解如何使用这个文件可以帮助开发者更有效地利用 Spring Boot 的特性,并构建更加模块化的应用程序。

主要作用

  • 定义自动配置类

    • 当创建一个新的 Spring Boot 应用程序时,Spring Boot 会根据你在项目中添加的依赖来推断你需要哪些自动配置。

    • spring.factories 文件中定义了与这些依赖相关的自动配置类。这些自动配置类会在 Spring Boot 启动时根据 classpath 中的 jar 包和配置自动进行 bean 的创建和配置。这些配置类通常带有 @Configuration 注解,并可以根据 classpath 中的类、库的存在或属性的值来条件性地配置 bean。例如,如果你添加了 MySQL 依赖,Spring Boot 可能会通过 spring.factories 文件找到并应用相应的数据库连接池配置。

  • SPI (Service Provider Interface) 实现:

    • Java 的 SPI 机制允许第三方开发者提供接口的实现,而无需修改主代码库。

    • spring.factories 文件就是一种基于文本的 SPI 配置方式,它指定了接口或抽象类的具体实现类,使得 Spring Boot 能够在运行时动态加载这些实现。

  • 扩展点的自动发现

    • Spring Boot 提供了许多扩展点(如 ApplicationListener, EnvironmentPostProcessor, ImportSelector 等),你可以通过 spring.factories 文件将自定义的实现类注册到这些扩展点上,从而影响应用程序的行为。

    • 当开发新的 Spring Boot 组件或模块时,可以通过在 META-INF 目录下创建 spring.factories 文件,并在其中指定相关的配置类,来让 Spring Boot 在启动时自动加载和配置这些组件或模块。

    • 这种方式简化了插件式开发,让开发者可以轻松地向 Spring Boot 应用程序添加功能而不必直接修改核心代码。

  • 事件监听器

    • 你可以注册事件监听器来响应应用程序生命周期中的特定事件,比如启动完成、环境准备就绪等。

    • 通过 spring.factories 文件,你可以声明实现了 ApplicationListener 接口的类,它们会在相应事件发生时被调用。

  • 初始化器

    • 如果你需要在应用程序启动之前执行某些初始化逻辑,可以通过 spring.factories 文件注册实现了 ApplicationContextInitializer 接口的类。
  • 配置加载优先级

    • 如果有多个 spring.factories 文件(比如,来自不同的 jar 包),Spring Boot 会加载并合并这些文件中的配置。如果存在相同的配置类,后加载的配置将覆盖先加载的配置。这种机制使得开发者可以灵活地覆盖或扩展框架的默认配置。

应用场景

  1. 模块化开发:将通用功能抽离到独立的模块中,并通过 spring.factories 文件让这些模块的配置类和 Bean 被自动加载。
  2. 第三方库集成:像 Spring Cloud、Spring Security 等都利用 spring.factories 提供自动配置能力,使得集成这些库变得更加简单和方便。
  3. 解耦配置:通过 spring.factories 文件提供自动化配置,而无需手动在主程序中引入配置类,从而实现了配置的解耦。
  4. 实现框架的定制和扩展: Spring 框架本身也使用了 spring.factories 文件来实现一些定制和扩展。这意味着你可以通过自定义的 spring.factories 文件来覆盖或替代 Spring 框架默认的行为,以满足特定的需求。

注意事项

  • 格式:每个键对应一个或多个逗号分隔的类名列表。注意不要忘记反斜杠 \ 来表示换行。
  • 命名规范:键名通常是某个接口或抽象类的全限定名,值则是其实现类的全限定名。
  • 加载顺序:所有通过 spring.factories 文件注册的类都会在应用程序启动期间被加载,但具体的加载顺序可能取决于 Spring 内部机制,并不是完全可控的。

使用示例

假设我们有一个自定义的自动配置类 MyAutoConfiguration 和一个事件监听器 MyApplicationListener

properties
# META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration

org.springframework.context.ApplicationListener=\
com.example.MyApplicationListener

SpringBoot 中Starters 的作用?

  1. 提供预配置的依赖: Spring Boot Starters 是一组预配置的依赖项集合,用于启用特定类型的功能。例如,你可以使用 spring-boot-starter-web 启用 Web 应用程序相关的功能,包括内嵌的 Web 服务器、Spring MVC、Jackson 等。这样,你只需引入这个 Starter,而无需单独处理每个依赖项的版本和配置。
  2. 简化依赖管理:每个starter本质上是一个POM文件(对于Maven)或build脚本(对于Gradle),它声明了该功能领域所需的库版本。Spring Boot 会自动处理它们的版本兼容性和配置。这有助于避免版本冲突和配置错误。
  3. 自动配置:Spring Boot的starters通常与自动配置(Auto-configuration)机制紧密合作。当检测到某些类存在于classpath上时,Spring Boot会尝试为你做出合理的默认配置。这意味着你不必从头开始编写冗长的XML或Java配置代码。
  4. 约定优于配置:Starters遵循“约定优于配置”的原则,提供了很多开箱即用的功能。然而,这也并不意味着你失去了对配置的控制;你可以随时覆盖默认设置以满足项目的特殊需求。
  5. 模块化开发:通过选择不同的starters,你可以将大型应用分解成更小、更专注的部分。比如,有专门用于数据访问层的spring-boot-starter-data-jpa,也有用于安全性的spring-boot-starter-security等。
  6. 自定义扩展: 尽管 Spring Boot Starters 提供了默认的依赖和配置,你仍然可以根据需要进行自定义扩展。你可以在自己的项目中覆盖默认的配置,添加额外的依赖项,或者通过属性配置文件来修改 Starter 的行为。
  7. 社区支持:除了官方提供的starters之外,还有许多由社区成员开发的第三方starters,涵盖了各种各样的技术栈和技术领域。这进一步扩展了Spring Boot的应用范围。

Spring Boot中的Starters是简化新项目配置的一种方式,它们是一组依赖描述符,当在构建工具(如Maven或Gradle)中引入这些starter依赖时,它会自动包含所有必要的库,并进行合理的默认配置。通过使用starters,开发者可以快速启动并运行应用程序,而不需要手动管理大量的依赖关系和配置。

SpringBoot 中Starters 的分类?

  1. Spring Boot应用类启动器:如spring-boot-starter-webspring-boot-starter-thymeleaf等,用于构建Web应用程序和提供模板引擎支持。
  2. Spring Boot生产启动器:如spring-boot-starter-actuatorspring-boot-starter-remote-shell等,用于生产环境的监控和管理。
  3. Spring Boot技术类启动器:如spring-boot-starter-data-jpaspring-boot-starter-data-redis等,用于访问数据库和缓存等。
  4. 其他第三方启动器:如mybatis-spring-boot-starterspring-boot-starter-security等,由第三方提供的用于扩展Spring Boot功能的启动器。

SpringBoot 常用的Starters?

Spring Boot 提供了一系列的 Starter POMs,它们简化了依赖管理和配置,使得开发者可以快速开始项目开发。以下是 Spring Boot 中常用的 Starter 列表及其简要描述:

核心Starter

  1. spring-boot-starter

    • 核心 Starter,包含了自动配置支持、日志和 YAML。
  2. spring-boot-starter-test

    • 用于测试的 Starter,包含 JUnit、Mockito、AssertJ 等测试框架的支持。

Web开发相关Starter

  1. spring-boot-starter-web

    • 包含构建基于 Spring MVC 的 web 应用程序所需的所有内容,默认使用内嵌 Tomcat 容器。
  2. spring-boot-starter-webflux

    • 支持响应式编程模型的Web应用程序,使用 Spring WebFlux 框架。
  3. spring-boot-starter-thymeleaf

    • 集成 Thymeleaf 模板引擎用于构建 HTML 页面。
  4. spring-boot-starter-freemarker

    • 集成 FreeMarker 模板引擎。
  5. spring-boot-starter-mustache

    • 集成 Mustache 模板引擎。

数据访问相关Starter

  1. spring-boot-starter-data-jpa

    • 使用 JPA(如 Hibernate)进行数据访问,集成 Spring Data JPA。
  2. spring-boot-starter-data-mongodb

    • 使用 MongoDB 进行 NoSQL 数据库操作,集成 Spring Data MongoDB。
  3. spring-boot-starter-data-redis

    • 使用 Redis 键值存储,集成 Spring Data Redis。
  4. spring-boot-starter-data-rest

    • 使用 Spring Data REST 来暴露 RESTful API。

安全与认证相关Starter

  1. spring-boot-starter-security

    • 集成 Spring Security,提供安全性和认证功能。
  2. spring-boot-starter-oauth2-clientspring-boot-starter-oauth2-resource-server

    • 分别用于 OAuth2 客户端和资源服务器的支持。

其他常用Starter

  1. spring-boot-starter-mail

    • 发送电子邮件的支持,通常与 JavaMailSender 接口一起使用。
  2. spring-boot-starter-validation

    • Bean 验证的支持,实现 JSR-303 (Bean Validation) 规范。
  3. spring-boot-starter-cache

    • 缓存抽象层的支持,可以轻松地集成多种缓存解决方案。
  4. spring-boot-starter-aop

    • 面向切面编程(AOP)的支持,通过 AspectJ 实现。
  5. spring-boot-starter-amqp

    • 使用 RabbitMQ 或其他 AMQP 消息代理的支持。
  6. spring-boot-starter-actuator

    • 提供生产就绪的功能,例如健康检查、度量指标等。
  7. spring-boot-starter-jdbc

    • JDBC 数据库访问的支持,适用于不需要 ORM 的场景。
  8. spring-boot-starter-json

    • JSON 处理的支持,通常包括 Jackson 库。
  9. spring-boot-starter-logging

    • 日志记录的支持,默认采用 SLF4J 和 Logback。

这些 Starters 只是 Spring Boot 生态系统中的一部分。根据你的具体需求,你可能会发现还有更多有用的 Starters。每个 Starter 都旨在减少设置和配置的时间,让开发者能够专注于业务逻辑的实现。

SpringBoot Starters命名规范?

  • Spring Boot官方的Starters都是以spring-boot-starter-命名的,代表了一个特定的应用类型。例如,spring-boot-starter-web用于构建Web应用程序,spring-boot-starter-data-jpa用于访问数据库等。
  • 第三方的Starters不能以spring-boot-开头命名,它们都被Spring Boot官方保留。一般一个第三方的Starter应该这样命名,如MyBatis的mybatis-spring-boot-starter

SpringBoot 使用Starters的注意事项?

  1. 版本兼容性:在引入Starters时,需要注意其版本与Spring Boot版本的兼容性。通常,Starters的版本号会与Spring Boot的版本号保持一致或相近。
  2. 依赖冲突:在项目中引入多个Starters时,可能会存在依赖冲突的问题。因此,在引入Starters之前,需要仔细分析项目的依赖关系,并选择合适的版本以避免冲突。
  3. 自定义配置:虽然Starters提供了默认的配置和功能,但在某些情况下,项目可能需要定制化配置。此时,可以通过覆盖Starters的默认配置来实现。

SpringBoot 切换内嵌的容器?

Spring Boot 默认使用内嵌的 Tomcat 作为它的 HTTP 容器,但也可以很方便地切换到其他容器,如 Jetty 或 Undertow。在构建文件中,需要做两件事:一是排除默认的 Tomcat 依赖,二是添加你想要使用的容器依赖。

对于 Maven (pom.xml)

xml
<dependencies>
  <!-- 其他依赖 -->

  <!-- 排除默认的Tomcat依赖 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
      <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

  <!-- 添加Jetty或Undertow依赖 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
  </dependency>

  <!-- 或者使用Undertow -->
  <!-- 
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
  -->
</dependencies>

对于 Gradle (build.gradle)

groovy
dependencies {
    // 排除默认的Tomcat依赖
    implementation('org.springframework.boot:spring-boot-starter-web') {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
    }

    // 添加Jetty或Undertow依赖
    implementation 'org.springframework.boot:spring-boot-starter-jetty'

    // 或者使用Undertow
    // implementation 'org.springframework.boot:spring-boot-starter-undertow'
}

SpringBoot 修改容器端口?

Spring Boot 应用的端口从默认的 8080 修改端口可以通过几种不同的方式来实现。

方法一:使用 application.propertiesapplication.yml 配置文件

application.properties
server.port=8081

application.yml

yaml
server:
  port: 8081

方法二:使用命令行参数

当你启动应用程序时,可以通过命令行参数覆盖配置文件中的设置。这种方法非常适合临时或动态地改变端口号,例如在不同环境中运行相同的应用程序时。

bash
java -jar your-spring-boot-app.jar --server.port=8081

方法三:使用 ServerProperties 类(不推荐直接修改代码)

可以直接在代码中配置端口,但这通常不推荐,因为这会使得配置变得不够灵活。创建一个配置类,并覆盖默认的 ServerProperties 设置:

java
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class ServerConfig {
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> containerCustomizer() {
        return (factory) -> factory.setPort(8081);
    }
}

方法四:使用环境变量

使用环境变量来设置端口。Spring Boot 会自动将环境变量转换为小写并用下划线代替点来匹配属性名。

Linux或者在 MacOS 上:

bash
export SERVER_PORT=8090

或者在 Windows 上:

bash
set SERVER_PORT=8090

在 Docker 容器中:

bash
docker run -e SERVER_PORT=8081 your-spring-boot-docker-image

方法五:使用 Spring Boot 的 application-{profile}.propertiesapplication-{profile}.yml

如果你使用了 Spring Boot 的 Profiles 功能,可以为不同的环境创建不同的配置文件。例如,为开发环境创建一个 application-dev.properties 文件:

properties
server.port=8082

application-prod.properties

bash
server.port=8081

然后在运行应用时指定 Profile:

bash
java -jar your-spring-boot-app.jar --spring.profiles.active=dev

方法六:Java 系统属性

通过 -D 参数传递给 JVM 来设置系统属性。

bash
java -Dserver.port=8090 -jar your-app.jar

SpringBoot 修改内嵌Tomcat服务器的配置?

在SpringBoot中,内嵌Tomcat服务器的配置可以通过两种方式实现:修改配置文件和自定义配置类。

一、通过配置文件进行配置

SpringBoot项目中的配置文件通常是application.propertiesapplication.yml。在这些文件中,你可以添加Tomcat相关的属性来调整其行为。

常用配置参数

  • server.port:配置Tomcat服务器的端口号,默认为8080。例如,server.port=8081将端口号设置为8081。
  • server.servlet.session.timeout:配置session失效时间,默认值为30分钟(30m)。如果不写单位,则默认单位是秒。但请注意,Tomcat中配置session过期时间是以分钟为单位,如果这里设置是秒的话,会自动转换为一个不超过所配置秒数的最大分钟数。
  • server.servlet.context-path:配置URL访问路径的基础路径,默认为/。如果配置了项目名称,那么在访问路径中要加上配置的路径。
  • server.tomcat.uri-encoding:配置Tomcat请求编码,默认值为UTF-8。

Tomcat性能优化核心参数

  • server.tomcat.max-connections:配置Tomcat的最大连接数,即并发数,默认值为8192或10000(具体默认值可能因SpringBoot版本而异)。
  • server.tomcat.accept-count:配置Tomcat启动的线程达到最大值时,接受排队的请求个数,默认值为100。
  • server.tomcat.connection-timeout:配置建立连接的超时时间,单位是毫秒,默认值为20000毫秒(某些SpringBoot版本中可能不同)。
  • server.tomcat.max-threads:配置Tomcat的最大线程数,默认值为200。这个值决定了Tomcat能够同时处理的最大请求数。
  • server.tomcat.min-spare-threads:配置Tomcat的最小空闲线程数,默认值为5或10(具体默认值可能因SpringBoot版本而异)。这个值决定了Tomcat在空闲时会保留的线程数,以便快速响应新的请求。

二、通过自定义配置类进行配置

如果你需要更复杂的配置,或者想要通过编程的方式动态地调整Tomcat的配置,你可以创建一个自定义的配置类。

  1. 建立一个配置类,并加上@Configuration注解。
  2. 在配置类中,创建一个ConfigurableServletWebServerFactory类型的Bean,并对其进行定制。
  3. 返回定制后的ConfigurableServletWebServerFactory实例。
java
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class TomcatConfig {
 
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
        return factory -> {
            factory.setPort(8082); // 设置端口号
            factory.setContextPath("/myapp"); // 设置上下文路径
            // 可以添加更多的定制逻辑,如设置线程池大小、连接超时时间等
        };
    }
}

在这个示例中,我们创建了一个名为TomcatConfig的配置类,并在其中定义了一个名为tomcatCustomizer的Bean。这个Bean实现了WebServerFactoryCustomizer<TomcatServletWebServerFactory>接口,并覆盖了customize方法。在customize方法中,我们可以对TomcatServletWebServerFactory进行各种定制操作,如设置端口号、上下文路径等。

请注意,虽然自定义配置类提供了更灵活的配置方式,但在大多数情况下,通过修改配置文件已经可以满足大部分需求。因此,在选择配置方式时,请根据你的具体需求和偏好进行选择。

SpringBoot 默认使用日志框架?

Spring Boot 默认使用 SLF4J(Simple Logging Facade for Java)作为日志门面,并且默认绑定到 Logback 作为底层日志实现。

日志框架层次结构

  • 日志门面 (Logging Facade):SLF4J

    • 提供了一个抽象层,使得你可以轻松地切换不同的日志实现。

    • 不直接负责日志的输出,而是通过桥接器将日志请求转发给实际的日志实现。

  • 日志实现 (Logging Implementation):Logback

    • 是一个强大的、基于Java的日志记录框架,能够提供丰富的功能和灵活的配置选项。

    • 被选为 Spring Boot 的默认日志实现,因为它与 SLF4J 集成良好,并且性能优异。

SpringBoot 中切换不同的日志框架?

在Spring Boot中切换不同的日志框架主要涉及以下几个步骤:

  1. 移除默认的日志依赖

    默认情况下,Spring Boot使用spring-boot-starter-logging作为其日志依赖,它内部包含了Logback。要切换到其他日志框架,首先需要从项目的依赖中排除这个默认的日志依赖。

    xml
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  2. 添加新日志框架的依赖:添加你选择的日志框架的依赖到项目中。以下是Log4j2日志框架的依赖配置:

    xml
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
  3. 配置日志框架:添加新日志框架的配置文件到src/main/resources目录下。例如,对于Log4j2,你可以添加log4j2.xmllog4j2-spring.xml文件;对于Logback,你可以添加logback-spring.xmllogback.xml文件。

  4. 重启应用:完成依赖配置和日志配置后,重启Spring Boot应用以使新的日志框架生效。

注意事项

  1. 依赖冲突:在切换日志框架时,确保没有引入相互冲突的依赖。例如,如果你添加了 Log4j2 的依赖,但又错误地保留了 Logback 的依赖,那么可能会导致日志输出混乱或应用程序启动失败。
  2. 配置文件命名:对于不同的日志框架,配置文件的命名可能有所不同。确保你使用了正确的配置文件命名约定。
  3. Spring Boot 版本:不同版本的 Spring Boot 可能对日志框架的支持有所不同。在切换日志框架之前,请查阅你正在使用的 Spring Boot 版本的官方文档,以确保兼容性。

SpringBoot 如何禁用web程序启动方式?

对于非Web应用程序,请在属性文件中禁用Web应用程序类型,application.properties 文件中添加:

properties
spring.main.web-application-type=none

SpringBoot 应用启动方式?

运行Spring Boot应用程序有多种方式,以下是几种常见的方法:

内嵌式服务器

  • 使用Maven或Gradle构建工具直接从命令行运行Spring Boot应用。通过mvn spring-boot:run(对于Maven)或./gradlew bootRun(对于Gradle)命令来启动应用。

  • 内嵌的Tomcat、Jetty或Undertow等服务器会自动配置并启动。

打包成可执行JAR/WAR文件

  • 构建项目后生成一个包含所有依赖、配置和资源的独立JAR或WAR文件。
  • 可以使用java -jar your-application.jar命令来运行这个JAR文件。
  • WAR文件可以部署到外部Servlet容器中,如Apache Tomcat。

IDE集成开发环境

  • 直接在IDE(如IntelliJ IDEA, Eclipse, 或 Spring Tool Suite (STS))中运行Spring Boot应用程序。
  • 通常只需点击“运行”按钮即可启动应用,IDE会处理编译和启动过程。

云平台部署

  • 部署到云服务提供商,如Heroku, AWS Elastic Beanstalk, Google App Engine, Azure等。
  • 这些平台通常支持直接上传JAR/WAR文件或者通过Git推送代码进行部署,并且能够自动处理应用的启动。

Docker容器化

  • 将Spring Boot应用打包进Docker镜像中,然后可以在任何安装了Docker的环境中运行该容器。
  • Docker提供了一致的运行环境,方便开发、测试和生产环境的一致性。

Kubernetes集群部署

  • 如果你使用的是微服务架构,可能会选择将Spring Boot应用部署到Kubernetes集群中。
  • Kubernetes提供了更高级别的自动化部署、扩展和服务发现功能。

根据具体的需求和场景,可以选择最适合的方式来运行Spring Boot应用程序。

SpringBoot 启动流程?

SpringBoot的启动流程是一个有序且复杂的过程,它涉及多个阶段和组件的初始化。以下是SpringBoot启动流程的详细步骤:

一、启动main方法

每个 Spring Boot 应用程序都有一个包含 main 方法的主类,通常这个类也标记有 @SpringBootApplication 注解。Spring Boot应用程序的启动入口是该类main方法,其中调用了SpringApplication.run()方法。这个方法是Spring Boot框架提供的,用于启动整个应用程序。

二、SpringApplication实例创建与初始化

在调用SpringApplication.run()方法之前,需要先创建一个SpringApplication对象。在SpringApplication对象的创建过程中,会进行一系列的初始化配置,包括:

  1. 设置资源加载器SpringApplication的构造方法会接收一个ResourceLoader参数(通常为null),并将其设置为资源加载器。
  2. 断言主要加载资源类:通过Assert.notNull()方法断言主要加载资源类(即启动类)不能为null
  3. 初始化主要加载资源类集合并去重:将启动类封装成LinkedHashSet,并注入到primarySources属性中。
  4. 检测Web应用程序类型:通过调用deduceWebApplicationType()deduceFromClasspath()方法,根据类路径中的相关类(如DispatcherServletDispatcherHandler等)来判断当前应用是响应式WEB应用(REACTIVE)、基于Servlet的WEB应用(SERVLET)还是非WEB应用(NONE)。
  5. 加载引导上下文的初始化器:加载BootstrapRegistryInitializer等初始化器,用于初始化引导上下文。
  6. 加载应用程序初始化器:从META-INF/spring.factories文件中读取ApplicationContextInitializer类的实例名称集合并去重,然后注入到initializers属性中。这些初始化器会在应用上下文创建之前被调用,用于在应用程序上下文创建之前进行初始化。
  7. 加载监听器:从META-INF/spring.factories文件中读取ApplicationListener类的实例名称集合并去重,然后注入到listeners属性中。这些监听器会监听应用启动过程中的各种事件。
  8. 设置主启动类:通过当前调用栈获取main方法所在类,并赋值给mainApplicationClass属性。

三、配置和执行SpringApplication

SpringApplication对象创建完成后,会调用其run()方法来启动应用程序。run()方法内部会执行以下步骤:

  1. 创建并启动计时监控类:创建一个StopWatch实例来监控整个启动过程的时间。
  2. 创建引导上下文:调用createBootstrapContext()方法创建引导上下文。
  3. 配置系统属性:设置系统属性java.awt.headless的值为true,用于运行headless服务器。
  4. 创建SpringApplicationRunListeners并发布应用启动事件:创建所有SpringApplicationRunListener实例(通常是EventPublishingRunListener),并发布应用启动事件。
  5. 准备环境:调用prepareEnvironment()方法准备环境。在这个过程中,会创建Environment实例(通常是ConfigurableEnvironment),并对其进行配置(如读取配置文件、设置属性等)。然后,触发监听器的environmentPrepared事件。
  6. 打印Banner:调用printBanner()方法打印应用程序的Banner信息(如果有的话)。
  7. 创建应用程序上下文:调用createApplicationContext()方法创建应用程序上下文(通常是AnnotationConfigServletWebServerApplicationContext)。
  8. 设置应用程序启动:调用setApplicationStartup()方法设置应用程序的启动信息。
  9. 准备应用程序上下文:调用prepareContext()方法准备应用程序上下文。在这个过程中,会保存环境信息、执行IOC容器的后置处理流程、应用初始化等。
  10. 刷新应用程序上下文:调用refreshContext(context)方法刷新应用程序上下文。这是Spring Boot启动流程中的核心步骤,涉及多个子步骤,包括配置工厂对象、注册并实例化Bean工厂发布处理器、注册并实例化Bean发布处理器、初始化与上下文有特别关系的Bean对象(如创建Tomcat服务器)、实例化所有Bean工厂缓存的Bean对象等。在启动过程中,Spring Boot 会发布一系列的应用上下文事件。
  11. 执行后续操作:调用afterRefresh()方法执行一些后续操作。
  12. 停止计时:停止计时并计算整个启动过程的时间。
  13. 通知监听器启动完成:调用监听器的started()方法,通知应用程序已经启动。
  14. 调用Runner:调用callRunners()方法执行所有的CommandLineRunnerApplicationRunner接口实现。

四、异常处理和启动完成

在启动过程中,如果出现异常,会调用handleRunFailure()方法处理异常,并抛出一个IllegalStateException异常。如果启动成功,会调用监听器的ready()方法,表示应用程序已经准备好,并返回创建的ConfigurableApplicationContext对象。

SpringBoot 的jar为什么可以直接运行?

Spring Boot 的 JAR 文件可以直接运行,主要是因为它们被打包为可执行的 JAR(也称为 "fat JAR" 或 "uber JAR"),并且包含了以下特性:

  • 嵌入式容器

    • Spring Boot 应用程序通常包含一个或多个嵌入式的 HTTP 服务器(如 Tomcat, Jetty, 或 Undertow),这些服务器被打包到应用程序的 JAR 文件中。

    • 因此,不需要单独安装和配置 Web 服务器来部署应用程序。

  • 启动类与 main 方法

    • 每个 Spring Boot 应用都有一个带有 main 方法的启动类,它是 Java 程序的入口点。

    • 在这个 main 方法中调用了 SpringApplication.run() 方法,它负责引导整个应用程序的启动过程。

  • 可执行JAR格式

    • 可执行 JAR 文件内部包含一个名为 META-INF/MANIFEST.MF 的清单文件。

    • 这个清单文件指定了 Main-Class 属性,告诉 JVM 哪个类包含 main 方法,以及 Class-Path 属性(如果需要)。

    • 对于 Spring Boot 的 JAR 文件,Main-Class 通常是 org.springframework.boot.loader.JarLauncher,它负责加载并启动应用程序。

  • 依赖库打包

    • Spring Boot使用spring-boot-maven-plugin或spring-boot-gradle-plugin插件来构建可执行的JAR文件。

    • 这些插件会将应用程序的所有依赖(包括Spring Boot的依赖和应用程序自身的依赖)一起打包到JAR文件的BOOT-INF/lib目录下。

  • Spring Boot 加载器

    • Spring Boot 提供了一组特殊的类加载器(位于 org.springframework.boot.loader 包下),用于处理从 JAR 内部加载资源的问题。

    • 这些加载器使得可以从 JAR 文件内正确地加载类、静态资源和其他必要的文件。

  • 命令行参数支持

    • 可执行 JAR 文件能够接收命令行参数,这允许在运行时动态修改应用行为,比如指定不同的配置文件或端口号等。
  • 环境变量和系统属性

    • 可以通过环境变量或系统属性轻松地覆盖默认设置,从而改变应用程序的行为,而无需重新打包。

由于以上原因,Spring Boot 的 JAR 文件可以在任何具有适当版本 JDK 的机器上直接使用 java -jar 命令运行,而无需额外的部署步骤。这种方式简化了应用程序的分发和部署流程,同时保持了高度的灵活性和可移植性。

SpringBoot 配置文件有哪几种格式?

Spring Boot 的配置文件主要有两种格式:propertiesYAML(yml)

properties 文件

  • 格式特点

    • 使用键值对(key=value)的方式进行配置。

    • 文件结构简单,易于理解和编辑。

    • 只支持键值对,不支持复杂的嵌套结构。

    • 不保证加载顺序,适用于简单的配置需求。

    • 支持通过 @PropertySource 注解导入配置。

    • 广泛支持,几乎所有编程语言和工具都支持这种格式。

    properties
    server.port=8080
    spring.datasource.url=jdbc:mysql://localhost:3306/mydb
    spring.datasource.username=root
    spring.datasource.password=secret

YAML(yml)文件

  • 格式特点

    • 使用“key: value”的形式存储配置信息。

    • 属性是有序的。

    • 不支持 @PropertySource 注解导入配置。

    • 支持 SpEl 表达式、松散绑定等高级功能。

    • 支持复杂的嵌套结构和列表。

    • 格式更加可读性强,易于表达复杂的配置信息。

    • 更加紧凑,减少了冗余字符。

    • 支持字面量、对象和数组三种数据结构,以及复合结构。

    • 支持内联注释(使用 # 开头)。

    • 大小写敏感,缩进表示层级关系,不能使用制表符(Tab)代替空格。

      yaml
      server:
        port: 8080
      spring:
        datasource:
          url: jdbc:mysql://localhost:3306/mydb
          username: root
          password: secret

主要区别

一、格式与结构

  1. application.properties

    • 使用键值对的方式进行配置,类似于传统的属性文件格式。

    • 没有层级结构,易于阅读和编写,但对于复杂配置可能显得不够灵活。

  2. application.yml

    • 使用层级结构和缩进来表示属性之间的关系,采用了YAML(YAML Ain't Markup Language)格式。

二、语法与规则

  1. application.properties

    • 使用“.”进行分割。

    • 没有特别严格的缩进要求。

  2. application.yml

    • 使用“:”进行分割。

    • 数据格式和JSON的格式很像,都是K-V格式,并且通过“:”进行赋值。

    • 缩进必须使用空格,不能使用制表符(Tab),否则会报错。

    • 每个key的冒号后面必须加一个空格。

三、优先级与兼容性

  1. 优先级:在Spring Boot项目中,如果application.propertiesapplication.yml两个文件中都配置了相同的属性,那么application.properties文件中的配置将覆盖application.yml文件中的配置。这意味着application.properties的优先级高于application.yml
  2. 兼容性:Spring Boot支持在application.propertiesapplication.yml中定义应用程序的属性,并会自动读取这些属性来配置应用程序的行为。因此,这两种文件在Spring Boot项目中是兼容的,可以根据项目需求选择使用。使用spring cloud的maven进行构造的项目,在把properties换成yml后,一定要进行mvn clean insatll

四、适用场景

  • 对于简单的配置,application.properties格式可能更加方便。
  • 对于复杂的配置,application.yml格式可以更清晰地表示属性之间的关系,因此更适合复杂的配置场景。

选择建议

  • 简单应用:如果你的应用程序配置比较简单,或者团队成员对 Properties 文件更为熟悉,那么继续使用 Properties 文件可能是最直接的选择。
  • 复杂应用:对于需要管理大量配置项或有多层嵌套配置的应用,YAML 文件通常会提供更好的可读性和维护性。
  • 混合使用:实际上,你可以同时使用 Properties 和 YAML 文件。例如,将基本配置放在 Properties 文件中,而将特定环境或复杂配置放在 YAML 文件里。

SpringBoot 的核心配置文件是什么?

Spring Boot 的核心配置文件主要有两个:bootstrap(可以是 .yml 或者 .properties 格式)和 application(同样可以是 .yml 或者 .properties 格式)。

一、配置文件的作用

bootstrap 配置文件

  • 加载顺序:bootstrap 配置文件由父 ApplicationContext 加载,且其加载优先级高于 application 配置文件,并且不会被覆盖或刷新。

  • 配置内容:bootstrap 配置文件主要用于系统层级的参数配置,这些配置通常与应用程序的启动和连接到外部配置中心相关,例如云服务配置、加密密钥等。

  • 特殊用途:在使用 Spring Cloud Config 配置中心时,需要在 bootstrap 配置文件中添加连接到配置中心的配置属性,以便加载外部配置中心的配置信息。

application 配置文件

  • 加载顺序:application 配置文件在 bootstrap 配置文件之后加载。
  • 配置内容:application 配置文件主要用于应用层级的参数配置,如数据库连接信息、服务器端口、日志级别等。
  • 格式选择:application.properties 文件使用 Java 的键值对格式来定义配置属性,而 application.yml 文件则使用更易读、易维护的 YAML 格式。

二、配置优先级

当存在多个同名配置项时,Spring Boot 会根据一定的顺序决定最终使用的值。一般而言,环境变量、命令行参数等具有更高的优先级,而 bootstrap.properties/yml 中的配置则会在 application.properties/yml 之前被加载,但其配置项不会被后者覆盖。

三、配置文件的详细对比

配置文件加载顺序配置内容格式选择备注
bootstrap.properties/bootstrap.yml优先加载系统层级参数配置,如外部配置中心连接信息properties(键值对)/ YAML(层级结构)适用于需要优先加载的配置,配置项不会被后者覆盖。
application.properties/application.yml后加载应用层级参数配置,如数据库连接、服务器端口等properties(键值对)/ YAML(层级结构)Spring Boot 的主要配置文件

四、环境特定配置文件

为了支持不同环境下的配置管理,Spring Boot 支持创建环境特定的配置文件。这些文件通常命名为 application-{profile}.propertiesapplication-{profile}.yml,其中 {profile} 是环境名称(如 dev, prod 等)。

  • 使用场景:当需要为开发、测试、生产等不同环境提供不同的配置时非常有用。
  • 激活方式:可以通过命令行参数 -Dspring.profiles.active=profileName 或者在主配置文件中通过 spring.profiles.active=profileName 来指定激活哪个配置文件。

五、配置文件的使用建议

  1. 尽量使用 application.yml:由于 YAML 格式支持层级结构,可以更加清晰地表达配置项之间的关系,因此建议使用 application.yml 而不是 application.properties。
  2. 注意配置文件的加载顺序:在 Spring Boot 中,配置文件的加载顺序是固定的,因此需要注意配置文件的命名和放置位置,以确保正确的加载顺序。
  3. 利用配置文件的占位符:在配置文件中,可以使用 ${…} 形式的占位符来引用其他配置属性的值,从而简化配置文件的编写。

样例

properties

properties
server.port=8081
spring.datasource.url=jdbc:mysql://localhost:3306/mydb

YAML

yaml
server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb

对比 application.yml 配置文件,bootstrap.yml配置文件具有以下几个特性:

  • boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载
  • boostrap 里面的属性不能被覆盖

bootstrap 配置文件有以下几个应用场景。

  • 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
  • 一些固定的不能被覆盖的属性
  • 一些加密/解密的场景

什么是 Spring Profiles?

Spring Profiles 是 Spring 框架中用于根据不同的环境(如开发、测试、生产等)来启用不同配置集的一种机制。通过使用 Profiles,你可以为同一个应用程序定义多套配置,并且在运行时选择其中一套来应用。这对于管理跨多个环境的应用程序非常有用,因为它允许你保持代码库的一致性,同时针对每个特定环境优化配置。

主要功能

  1. 条件化加载 Bean:可以基于激活的 Profile 来决定是否创建某些 Bean。
  2. 环境特定配置文件:支持为不同 Profile 创建独立的配置文件,如 application-dev.propertiesapplication-prod.yml
  3. 动态切换配置:可以在不改变代码的情况下,通过命令行参数、环境变量或系统属性等方式激活不同的 Profile。

定义 Profile-Specific 配置文件

可以创建与 Profile 相关的配置文件,这些文件通常命名为 application-{profile}.propertiesapplication-{profile}.yml

  • application-dev.properties:包含开发环境的配置。
  • application-prod.yml:包含生产环境的配置。

激活 Profile

  • 可以通过多种方式激活一个或多个 Profiles:

  • 命令行参数:使用 -Dspring.profiles.active=profileName 参数启动应用。

    bash
    java -jar myapp.jar -Dspring.profiles.active=dev
  • 环境变量:设置 SPRING_PROFILES_ACTIVE 环境变量。

    export SPRING_PROFILES_ACTIVE=prod
  • 系统属性:通过 Java 系统属性指定。

    System.setProperty("spring.profiles.active", "test");
  • 配置文件 声明application.properties application.yml 文件:直接在主配置文件中声明。

    properties
    spring.profiles.active=dev

    或者在 YAML 文件中:

    yaml
    spring:
      profiles:
        active: dev
  • 使用 @Profile 注解:你可以使用 @Profile 注解来标记类或方法,使得它们仅在特定的 Profile 下生效。

    java
    @Configuration
    @Profile("dev")
    public class DevelopmentConfig {
        // 开发环境特有的配置
    }
  • 多个 Profiles 的组合:如果需要同时激活多个 Profiles,可以用逗号分隔它们的名字:

    properties
    spring.profiles.active=dev,db-oracle 
    #这将同时激活名为 dev 和 db-oracle 的两个 Profiles。

注意事项

  • 优先级

    • 如果存在相同属性的不同Profile-Specific配置文件,则激活的Profile中的配置会覆盖默认配置。

    • 开发者需要注意配置文件的优先级和覆盖规则,以避免配置冲突和不必要的覆盖。

  • 安全性和敏感信息

    • 对于敏感数据(如密码),开发者应考虑使用加密存储或环境变量来代替直接硬编码在配置文件中。
  • 调试配置

    • 利用spring.config.import可以方便地导入额外的配置文件,这对于调试非常有用。

Spring Profiles是Spring框架提供的一种灵活的配置管理方式,它允许开发者根据不同的环境需求为应用程序提供不同的配置选项。通过合理使用Spring Profiles,开发者可以方便地管理和切换不同环境下的配置,提高应用程序的可移植性和安全性。

SpringBoot 配置加载顺序优先级是怎么样的?

Spring Boot 的配置加载顺序遵循一定的优先级规则,确保开发者可以在不同层次上覆盖默认配置。以下是 Spring Boot 配置加载的优先级列表,从最高优先级(最晚加载,可以覆盖之前的配置)到最低优先级排列:

  1. 开发者工具Devtools 全局配置参数;

  2. 单元测试上的@TestPropertySource 注解指定的参数;

  3. 单元测试上的@SpringBootTest 注解指定的参数;

  4. 命令行参数 (--key=value)

    • 通过命令行启动应用程序时传递的参数。

    • java -jar myapp.jar --server.port=9000

  5. 来自 SPRING_APPLICATION_JSON 的属性(嵌入在环境中)

    • 这是一个环境变量,其值为 JSON 字符串格式,允许动态地设置或覆盖配置属性。

    • SPRING_APPLICATION_JSON='{"key":"value"}’

  6. ServletConfig 初始化参数

    • 如果应用程序是 Web 应用程序,并且使用了 Servlet API,那么这些初始化参数会生效。
  7. ServletContext 初始化参数

    • 类似于 ServletConfig 参数,但作用范围更大,适用于整个 Web 应用程序上下文。
  8. JNDI 属性 (java:comp/env)

  9. Java 系统属性 (System.getProperties())

    • 通过 -D 参数传递给Java虚拟机的属性。
  10. 操作系统的环境变量

  11. 随机生成的值(例如 random.value, random.int 等)

    • 使用 RandomValuePropertySource 提供的随机值。
  12. 打包 jar 外部的 profile-specific 配置文件 (application-{profile}.properties .yml)

    • 放置在类路径根目录或 config 子目录下的特定 profile 配置文件。
  13. 打包 jar 内部的 profile-specific 配置文件

    • 打包进 JAR 文件中的 application-{profile}.properties.yml 文件。

    • 默认配置文件,通常放在 src/main/resources/ 下。

  14. 打包 jar 外部的主配置文件 (application.properties .yml)

    • 放置在类路径根目录或 config 子目录下的主配置文件。
  15. 打包 jar 内部的主配置文件

    • 打包进 JAR 文件中的 application.properties.yml 文件。

    • 默认配置文件,通常放在 src/main/resources/ 下。

  16. @Configuration 类上的 @PropertySource 注解

    • 直接在配置类中指定的属性源。
  17. 默认属性(通过 SpringApplication.setDefaultProperties 指定)

  • 在应用程序启动前设定的默认属性。

加载顺序的详细解释

Profile-specific 配置文件

  • 如果激活了多个 profiles,那么所有对应的 profile-specific 配置文件都会被加载,但是后加载的可以覆盖先加载的同名属性。

bootstrap 配置文件的优先加载

  • bootstrap 配置文件由父 ApplicationContext 加载,因此其配置信息在应用程序启动时首先被加载。
  • 这使得 bootstrap 配置文件中的配置能够优先于其他配置文件生效,特别是在需要连接到外部配置中心时。
  • 请注意,bootstrap.properties/yml 主要用于 Spring Cloud 项目。

application 配置文件的加载

  • 在 bootstrap 配置文件之后,Spring Boot 会加载 application 配置文件。
  • application 配置文件中的配置将覆盖 bootstrap 配置文件中相同名称的配置(如果存在)。

命令行参数和环境变量的覆盖

  • 命令行参数和环境变量具有最高的优先级,可以覆盖任何配置文件中的配置。
  • 这使得开发者能够在启动应用程序时灵活地调整配置。

Java系统属性的覆盖

  • Java系统属性虽然优先级较低,但仍然可以覆盖配置文件中的某些配置。
  • 这通常用于在启动 Java 应用时通过命令行传递系统属性来指定配置值。

外部化配置的优先级

  • Spring Boot 支持从文件系统中加载配置文件,比如通过 spring.config.location 指定额外的配置文件位置,这些文件也会按照上述规则参与加载。
  • 外部化配置(如外部属性文件)的优先级通常低于配置文件中的配置,但高于命令行参数和环境变量之外的配置。
  • 这使得开发者能够在不修改应用程序代码的情况下灵活地调整配置。

注意事项

  1. 配置文件的命名和位置

    • Spring Boot 会按照特定的顺序扫描和加载配置文件。因此,开发者需要注意配置文件的命名和位置,以确保正确的加载顺序。
  2. 配置属性的覆盖规则

    • 在配置加载过程中,如果多个配置文件或属性源中存在相同的配置属性,则后加载的属性将覆盖先加载的属性。

    • 开发者需要了解这一规则,以避免配置冲突和不必要的覆盖。

  3. 使用占位符引用其他配置

    • 在配置文件中,可以使用 ${...} 语法来引用其他属性的值。这种方式可以创建依赖关系,使得某些属性在其他属性被解析后才能确定其值。

SpringBoot 读取配置文件配置的方式?

Spring Boot 提供了多种读取配置的方式,以下是主要的几种方法:

  1. 使用 @Value 注解

    • 适合读取简单的单一属性。

    • 可以直接应用于字段、构造函数或方法参数上,Spring 会直接将配置值注入到对应的字段或参数中。

      java
      @Component
      public class MyComponent {
          @Value("${app.name}")
          private String name;
          
          // 构造函数注入
          public MyComponent(@Value("${app.name}") String name) {
              this.name = name;
          }
          
          // 方法参数注入
          @Value("${app.name}")
          public void setName(String name) {
              this.name = name;
          }
      }
  2. 使用 @ConfigurationProperties 注解

    • 适合读取复杂的配置集,如嵌套属性或集合类型。

    • 在配置类上使用 @ConfigurationProperties 注解,并指定前缀,该类会直接映射配置文件中与前缀匹配的属性。

      java
      @Component
      @ConfigurationProperties(prefix = "app")
      public class AppProperties {
          private String name;
          private List<String> keys;
          
          // getter 和 setter 方法
      }
  3. 使用 Environment 对象

    • 提供了访问配置信息的方法,适合在运行时动态访问配置。

    • 通过注入 Environment 对象来获取配置属性值。

      java
      @Component
      public class MyComponent {
          @Autowired
          private Environment environment;
          
          public void printConfig() {
              String port = environment.getProperty("server.port");
              System.out.println("Server Port: " + port);
          }
      }
  4. 使用 @PropertySource 注解

    • 允许指定额外的属性文件作为配置源,适用于读取非 application.properties 或 application.yml 文件中的配置。

    • 在配置类上使用 @PropertySource 注解来加载指定的配置文件,并使用 @Value 注解或 Environment 对象获取属性。

      java
      @Configuration
      @PropertySource("classpath:custom.properties")
      public class AppConfig {
          // 可以使用 @Value 注解或 Environment 对象来获取配置属性
      }
  5. 自定义配置文件读取

    • 适用于读取非标准的配置文件(如 JSON、XML 等)。

    • 通过编写自定义的配置文件读取逻辑来实现,例如使用 Jackson 库来读取 JSON 配置文件。

SpringBoot 配置文件进行加密?

在SpringBoot中,对配置文件进行加密是保护敏感信息(如数据库密码、API密钥等)的重要措施。以下是几种常见的加密方法:

使用Jasypt进行加密

Jasypt是一个Java加密库,它提供了强大的加密功能,并且可以与SpringBoot轻松集成。

  1. 引入Jasypt依赖:在pom.xml文件中添加Jasypt的依赖项。

    xml
    <dependency>
    	<groupId>com.github.ulisesbocchio</groupId>
    	<artifactId>jasypt-spring-boot-starter</artifactId>
    	<version>3.0.4</version> <!-- 请根据需要选择最新版本 -->
    </dependency>
    
    <plugin>
    	<groupId>com.github.ulisesbocchio</groupId>
    	<artifactId>jasypt-maven-plugin</artifactId>
    	<version>3.0.4</version> <!-- 请根据需要选择最新版本 -->
    </plugin>
  2. 配置Jasypt:在application.propertiesapplication.yml文件中添加Jasypt的配置项,如加密算法的盐值等。

    yaml
    jasypt:
      encryptor:
        algorithm: PBEWithMD5AndDES
        password: yourSaltValue # 盐值
  3. 加密配置文件中的敏感信息

    • 生成密钥:使用 Jasypt 提供的命令行工具或其他方式生成一个加密密钥,并将其保存在一个安全的地方(例如环境变量或单独的文件中)。

    • 加密配置文件中的值:使用 Jasypt 工具加密你想要保护的配置项。也可以通过 Maven 插件生成

      bash
      echo "mysecretvalue" | jasypt encryptor -algorithm PBEWITHHMACSHA512ANDAES_256 -password mypassword

      Maven

      bash
      mvn jasypt:encrypt-value -Djasypt.encryptor.password="xushu666" -Djasypt.plugin.value="123456"
    • 修改配置文件:将加密后的值放入配置文件中,前缀加上 ENC()

      properties
      spring.datasource.password=ENC(encryptedPassword)
  4. 启动项目:当SpringBoot项目启动时,它会自动识别ENC()包裹的密文,并使用配置的Jasypt加密器进行解密。

使用自定义加解密算法

  • 对于特定需求,也可以开发自己的加密解决方案。这可能涉及到编写自定义的 PropertySourceEnvironmentPostProcessor 来读取加密的配置文件并在应用程序启动时解密它们。

    java
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.core.env.MapPropertySource;
    import org.springframework.stereotype.Component;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Component
    public class CustomDecryptor implements ApplicationListener<ContextRefreshedEvent> {
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            ConfigurableEnvironment env = (ConfigurableEnvironment) event.getApplicationContext().getEnvironment();
            Map<String, Object> decryptedProperties = new HashMap<>();
    
            // 假设我们有一个方法可以从加密的属性中提取并解密值
            decryptProperties(env.getPropertySources(), decryptedProperties);
    
            // 将解密后的属性添加到环境中
            env.getPropertySources().addFirst(new MapPropertySource("decryptedProperties", decryptedProperties));
        }
    
        private void decryptProperties(MutablePropertySources propertySources, Map<String, Object> decryptedProperties) {
            // 实现具体的解密逻辑
        }
    }

注意事项

  • 安全性:无论选择哪种方法,确保加密密钥的安全存储非常重要。不要将密钥硬编码到源代码中;相反,应该使用环境变量、外部密钥管理服务或者其他安全的方式传递密钥。
  • 性能影响:加密和解密过程会带来一定的性能开销,因此需要评估其对应用程序的影响。
  • 备份和恢复:确保有适当的备份和恢复策略,以防丢失解密密钥导致无法访问重要配置。
  • 兼容性:确保所选的加密方法与SpringBoot版本兼容,并遵循相关的最佳实践。

SpringBoot Actuator 作用?

SpringBoot Actuator 是 Spring Boot 框架提供的一个子项目,它主要用于对 Spring Boot 应用进行监控和管理。通过 Actuator,开发者可以轻松地获取应用的各种内部信息,比如健康状况、度量信息、环境变量等,同时还可以通过它来执行一些管理任务,比如关闭应用、触发垃圾回收等。

Actuator 的主要作用包括:

  1. 健康检查: Actuator 提供了健康检查端点,可以监控应用的运行状态。通过访问这个端点,开发者可以快速地了解应用是否运行正常,以及各个组件的健康状况。
  2. 度量信息收集: Actuator 可以收集并暴露应用的度量信息,比如内存使用情况、线程数量、垃圾回收次数等。这些信息对于监控应用的性能和瓶颈非常有用。
  3. 日志和跟踪: Actuator 提供了日志和跟踪相关的端点,可以帮助开发者查看应用的日志信息和跟踪请求的处理过程。
  4. 应用管理: 通过 Actuator,开发者可以执行一些应用级别的管理操作,比如关闭应用、触发垃圾回收等。这些操作对于维护应用的稳定性和性能非常有帮助。
  5. 环境信息查看: Actuator 还可以暴露应用的环境信息,比如配置文件的内容、系统属性等。这些信息对于调试和配置应用非常有用。
  6. 自定义扩展: Actuator 提供了灵活的扩展机制,允许开发者根据自己的需求定制新的端点和功能。

SpringBoot Actuator 是一个功能强大且易于使用的监控和管理工具,它可以帮助开发者更好地了解和管理自己的 Spring Boot 应用。需要注意的是,由于 Actuator 暴露了一些敏感信息和操作,因此在使用时需要特别注意安全性。建议通过 Spring Security 等安全框架来限制对这些端点的访问,确保只有授权的用户才能访问和操作。

SpringBoot 常用Actuator端点?

Actuator提供了多种端点(Endpoints),每个端点都暴露了一些特定的信息。

健康检查

  • 通过/actuator/health端点检查应用的健康状态,包括数据库连接、磁盘空间等。你可以通过自定义HealthIndicator来扩展健康检查逻辑。

度量指标

  • /actuator/metrics端点提供了各种运行时度量数据,如内存使用情况、线程数、HTTP请求计数等。你还可以自定义度量以跟踪特定业务逻辑。

环境属性

  • 使用/actuator/env端点可以查看应用程序的环境属性,包括系统属性、环境变量以及配置文件中的设置。

信息端点

  • /actuator/info端点允许你展示关于应用程序的任意信息,比如版本号、构建时间等。这些信息通常是静态的,并且可以从build-info插件生成的META-INF/build-info.properties文件中读取。

Beans及其相关信息:

  • /actuator/beans 列出所有Spring容器中的Bean及其相关信息。

自动配置:

  • /actuator/conditions显示哪些条件导致了某些自动配置类被包含或排除。

审计事件

  • /actuator/auditevents端点记录了所有被标记为审计事件的操作,这对于追踪关键业务流程非常重要。

日志级别管理

  • /actuator/loggers端点可以用来动态调整应用程序的日志级别,方便调试问题而不必重启服务。

线程转储

  • /actuator/threaddump端点能够提供当前Java虚拟机中所有线程的状态快照,有助于诊断死锁等问题。

配置属性:

  • /actuator/configprops展示所有@ConfigurationProperties配置的值,帮助理解配置项的来源。

HTTP追踪

  • /actuator/httptrace端点收集并展示了最近的HTTP请求/响应交换信息,默认情况下会保留最后100个请求。

映射

  • /actuator/mappings列出所有的URL路径映射,即控制器方法与URL之间的关联。

计划任务

  • /actuator/scheduledtasks 列出所有已注册的任务调度器和它们的执行计划。

数据库迁移状态

  • /actuator/flyway/actuator/liquibase 分别显示Flyway或Liquibase数据库迁移的状态。

JMX MBeans:

  • /actuator/jolokia:一个代理,允许你通过HTTP访问JMX MBeans,方便远程管理和监控。

关闭应用

  • 如果启用了相应的端点(默认是禁用的),则可以通过/actuator/shutdown来优雅地关闭应用。

其他特性

  • 自定义短点

SpringBoot Actuator 配置步骤?

SpringBoot Actuator的配置步骤主要包括以下几点:

一、添加依赖

首先,需要在项目的构建配置文件中添加Actuator的依赖。对于Maven项目,需要在pom.xml文件中添加以下依赖:

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

对于Gradle项目,则需要在build.gradle文件中添加如下依赖:

groovy
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

二、配置端点

接下来,需要在application.propertiesapplication.yml文件中配置Actuator的端点。

  1. 暴露端点

    • 通过management.endpoints.web.exposure.include属性来指定哪些端点是暴露的。例如,要暴露所有端点,可以设置为*;如果只想暴露特定的端点,如healthinfo,则可以设置为health,info
  2. 定制端点

    • 可以根据实际需求定制端点的行为。例如,通过management.endpoint.health.show-details属性来控制健康检查端点的详细信息显示权限。将其设置为always,则端点将显示所有的健康信息;设置为when-authorized,则只有授权的用户才能看到详细的健康信息。
  3. 修改端点URL路径

    • 使用management.endpoints.web.base-path属性来修改Actuator端点的URL路径。例如,将其设置为/admin,则所有Actuator端点的URL都将以/admin开头。

三、配置安全性

为了确保Actuator端点的安全性,可以采取以下措施:

使用Spring Security

  • 如前所述,可以添加Spring Security依赖,并通过配置类来指定访问规则。

添加认证信息

  • application.propertiesapplication.yml文件中添加用户名、密码和角色等认证信息。例如:
properties
spring.security.user.name=admin
spring.security.user.password=secret
spring.security.user.roles=ADMIN

四、启动应用

完成上述配置后,启动Spring Boot应用程序。Actuator组件将自动启用,并且可以通过特定的URL访问相关的端点。例如,要访问健康检查端点,可以访问http://localhost:8080/actuator/health(假设应用程序运行在本地,且端口号为8080)。

五、验证配置

最后,通过访问Actuator端点来验证配置是否正确。例如,可以访问健康检查端点来查看应用程序的健康状况;访问度量信息端点来查看应用程序的度量数据等。

SpringBoot Actuator 端点的访问权限如何控制?

控制Spring Boot Actuator端点的访问权限是确保应用程序安全性的重要部分。默认情况下,Actuator端点的安全配置取决于你是否在项目中启用了安全模块(如Spring Security)。如果没有显式地添加安全模块,那么默认只有/actuator/health/actuator/info这两个端点是公开的,其他端点则需要通过认证才能访问。

控制端点访问权限的方法

  1. 使用Spring Security进行细粒度控制

    如果已经在项目中集成了Spring Security,可以通过定义安全规则来保护Actuator端点。这种方法提供了非常灵活的安全策略,可以根据业务需求定制哪些用户或角色可以访问特定的端点。

    java
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    // 允许匿名访问健康检查端点
                    .antMatchers("/actuator/health").permitAll()
                    // 所有其他端点都需要身份验证
                    .antMatchers("/actuator/**").authenticated()
                .and()
                // 配置登录表单等
                .formLogin();
        }
    }
  2. 使用management.security.enabled属性(已废弃)

    在较早版本的Spring Boot中,有一个简单的开关management.security.enabled用于启用或禁用所有Actuator端点的安全性。但是从Spring Boot 2.x开始,这个属性已经被移除,推荐使用更现代的方式来进行安全配置。

  3. 通过application.propertiesapplication.yml文件控制暴露的端点

    可以直接在配置文件中指定哪些端点应该被公开,而不需要额外的安全层。

    properties
    # application.properties
    management.endpoints.web.exposure.include=health,info,metrics

    或者使用YAML格式:

    yaml
    # application.yml
    management:
      endpoints:
        web:
          exposure:
            include: health,info,metrics
  4. 自定义安全策略

    如果需要更加精细的控制,比如基于用户角色来限制对某些端点的访问,可以在application.propertiesapplication.yml中定义自定义的安全表达式。

    properties
    # application.properties
    # 这会使得`/actuator/health`端点仅限于拥有ADMIN角色的用户访问,而 /actuator/metrics 端点则对USER和ADMIN角色开放。
    management.endpoint.health.roles=ADMIN
    management.endpoint.metrics.roles=USER,ADMIN
  5. 使用Spring Boot Admin或其他监控工具

    对于生产环境下的应用,考虑使用专门的监控工具,如Spring Boot Admin,它可以集中管理和可视化多个Spring Boot应用的状态,并且自带了安全特性来管理对各个端点的访问。

SpringBoot 默认动态代理?

Spring Boot 默认使用 CGLIB 动态代理而不是 JDK 动态代理,主要是基于以下几个原因:

  1. 对非接口类的支持

    • JDK 动态代理:仅支持对接口的代理。这意味着如果你想要代理一个类,这个类必须实现至少一个接口。对于没有接口的类,JDK 动态代理将无法创建代理实例。CGLIB 动态代理:可以代理任何类,无论该类是否实现了接口。它通过继承被代理类并重写其方法来实现这一点。这使得 CGLIB 在处理那些没有提供接口的类时更加灵活。
  2. 性能考虑

    • CGLIB 动态代理:在某些情况下,尤其是当需要创建大量代理对象时,Cglib通常比JDK动态代理更快。这是因为Cglib通过创建目标类的子类来实现代理,避免了JDK动态代理所需的额外反射调用,从而提高了性能。
    1. AOP(面向切面编程)的需求
    • Spring 的 AOP 框架需要能够代理任意的类和方法,以便于织入横切关注点(如事务管理、日志记录等)。由于很多实际应用中的类并不一定都实现了接口,为了确保所有类都可以被代理,Spring 选择默认使用 CGLIB。
  3. 简化配置

    • 为了让开发者更容易上手和使用 Spring Boot,减少配置复杂度是一个重要的考量因素。默认使用 CGLIB 可以避免开发者需要为每个没有接口的类手动配置代理策略的问题。
  4. 与第三方库的兼容性

    • 许多流行的框架和库(例如 Hibernate)内部也使用了 CGLIB 来实现动态代理。因此,默认使用 CGLIB 可以提高与这些库的兼容性和集成便利性。

    • Spring Boot 选择 Cglib 动态代理可以使你的类无需实现任何接口或继承特定的类,从而减少了对源代码的侵入性。这对于集成第三方库或需要代理的现有类特别有用。

注意事项

  • final 方法不可代理:因为 CGLIB 是通过继承实现的,所以它不能代理 final 类或 final 方法。
  • 额外的依赖:使用 CGLIB 需要引入额外的库依赖(如 cglibasm),这可能会增加应用程序的大小。
  • 切换为 JDK 动态代理:可以通过设置 proxy-target-class=false 来切换到 JDK 动态代理模式。

SpringBoot 是否允许循环依赖?

从Spring Boot 2.6.0版本开始,默认禁止了循环依赖,如果程序中出现循环依赖就会报错。之前的版本SpringBoot 默认情况下允许单例(Singleton)作用域下的属性循环依赖,但不允许构造器循环依赖。

如果需要使用循环依赖,可以通过以下方式进行配置:

  1. application.propertiesapplication.yml中添加配置

    application.properties中添加

    properties
    spring.main.allow-circular-references=true

    application.yml中添加

    yaml
    spring:
      main:
        allow-circular-references: true
  2. 在启动类中设置

    在Spring Boot的启动类中通过SpringApplicationBuilder来允许循环依赖:

    java
    public static void main(String[] args) {
    	new SpringApplicationBuilder(Application.class)
    		.allowCircularReferences(true) // 允许循环引用
    		.run(args);
    }

SpringBoot 线上热部署有哪几种方式?

在Spring Boot中实现线上热部署主要有以下几种方式:

Spring Boot DevTools(不推荐)

  • 通过在项目的pom.xml中添加spring-boot-devtools依赖来实现快速重启而非真正的热部署。

  • 它能够监控classpath下的文件变化,并在检测到变化时重启应用,从而加快开发过程中的反馈循环。

  • 在线上环境中,通常不推荐使用DevTools,因为它会增加额外的资源消耗,并且可能带来不稳定因素。

JRebel

  • JRebel是一个商业热部署工具,它支持广泛的框架和技术,能够在不重启应用的情况下即时更新代码和配置的更改。
  • 它通过在运行时修改类的字节码来实现热部署,并且可以处理资源文件的更新。

Spring Loaded

  • Spring Loaded是一个插件,它能够监听类文件的变化并重新加载它们,但它不支持Spring Boot的自动配置。

DCEVM + HotswapAgent

  • DCEVM是一个Java虚拟机,它支持在运行时重新定义类。
  • HotswapAgent是一个代理程序,用于支持类文件的热部署。

Docker + 文件挂载

  • 使用Docker部署应用程序时,可以将代码和资源文件挂载到容器中,实现实时更新代码而无需重启容器。

自定义热部署实现(使用类加载器和文件监听机制)

  • 基于Java的类加载器和文件监听机制实现自定义热部署。通过创建自定义类加载器,在检测到类文件变化时重新加载类。同时,使用文件监听机制(如Java NIO的WatchService)来监听项目文件的变化。

这些方法可以帮助开发者在开发过程中减少重启应用的频率,提高开发效率。需要注意的是,热部署在某些情况下可能会导致状态不一致或内存泄漏,因此在生产环境中应谨慎使用。

SpringBoot 启动的时候运行一些特定的代码?

在Spring Boot启动的时候运行一些特定的代码,可以通过多种方式实现。以下是几种常见的方法:

使用CommandLineRunnerApplicationRunner接口

CommandLineRunnerApplicationRunner是Spring Boot提供的两个接口,用于在应用程序启动后运行一些特定的代码。它们的主要区别在于接收命令行参数的方式不同。

  • CommandLineRunner:接收的是字符串数组形式的命令行参数。

  • ApplicationRunner:接收的是ApplicationArguments对象,该对象提供了更丰富的方法来处理命令行参数。

使用这两个接口时,需要创建一个类并实现相应的接口,然后在run方法中编写要在启动时执行的代码。

java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
 
@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("Application started with command line arguments: " + java.util.Arrays.toString(args));
    }
}
 
@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        System.out.println("Application started with application arguments: " + args.getNonOptionArgs());
    }
}

使用Spring Boot的事件机制

Spring Boot提供了一个事件驱动的架构,允许开发者在应用程序的不同阶段发布和监听事件。通过使用事件机制,可以在应用程序启动、关闭等阶段执行特定的代码。例如,可以创建一个监听ApplicationReadyEvent事件的类或使用**@EventListener**注解

java
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
 
@Component
public class MyApplicationListener {
    @EventListener
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        System.out.println("MyApplicationListener is started up");
    }
}

使用ServletContextListener接口(适用于Web应用)

在Web应用程序中,还可以实现ServletContextListener接口,并在contextInitialized方法中编写要在启动时执行的代码。但是,这种方法更适用于传统的Servlet/JSP应用程序,而不是纯粹的Spring Boot应用程序。在Spring Boot中,通常推荐使用上述其他方法。

注意事项

  1. 当有多个类实现了CommandLineRunnerApplicationRunner接口时,可以通过在类上添加@Order注解来设定运行顺序。
  2. Spring Boot的事件机制提供了丰富的功能,但应谨慎使用,以避免过多的事件监听器影响应用程序的性能。

通过以上方法,可以在Spring Boot启动时运行特定的代码,以满足不同的业务需求。

SpringBoot如何支持CORS跨域访问?

在Spring Boot应用程序中,处理跨域资源共享(CORS, Cross-Origin Resource Sharing)的需求非常常见。Spring Boot 提供了几种方式来配置 CORS 支持。以下是一些常见的方法:

  1. 使用 @CrossOrigin 注解

    可以在具体的控制器或方法上使用 @CrossOrigin 注解来允许跨域请求。

    java
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    @RestController
    @RequestMapping("/api")
    public class MyController {
        @CrossOrigin(origins = "http://example.com")
        @GetMapping("/data")
        public String getData() {
            return "Hello, World!";
        }
    }
    1. 全局配置 CORS

      方式一:可以创建一个配置类来实现 WebMvcConfigurer 接口,并覆盖 addCorsMappings 方法。

      java
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.config.annotation.CorsRegistry;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
       
      @Configuration
      public class WebConfig implements WebMvcConfigurer {
       
          @Override
          public void addCorsMappings(CorsRegistry registry) {
              // 在这个例子中,所有匹配 /api/** 路径的请求都将允许来自 http://example.com 和 http://another-example.com 的跨域请求,
              // 并且允许指定的 HTTP 方法和头信息。
              registry.addMapping("/api/**")
                      .allowedOrigins("http://example.com", "http://another-example.com")
                      .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                      .allowedHeaders("*")
                      .allowCredentials(true);
          }
      }

      方式二:使用 CorsFilter,可以创建一个自定义的 CorsFilter 来实现更复杂的 CORS 配置。

      java
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.filter.CorsFilter;
       
      import javax.servlet.FilterConfig;
      import javax.servlet.ServletException;
      import javax.servlet.FilterChain;
      import javax.servlet.Filter;
      import javax.servlet.ServletRequest;
      import javax.servlet.ServletResponse;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
       
      @Configuration
      public class CorsConfig {
        // 在这个例子中,我们创建了一个 `CorsFilter` 并通过 `FilterRegistrationBean` 注册它。
        // 这个 `CorsFilter` 将会应用于所有的请求路径。
          @Bean
          public FilterRegistrationBean<CorsFilter> corsFilter() {
              UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
              CorsConfiguration config = new CorsConfiguration();
              config.setAllowCredentials(true);
              config.addAllowedOrigin("http://example.com");
              config.addAllowedOrigin("http://another-example.com");
              config.addAllowedHeader("*");
              config.addAllowedMethod("GET");
              config.addAllowedMethod("POST");
              config.addAllowedMethod("PUT");
              config.addAllowedMethod("DELETE");
              config.addAllowedMethod("OPTIONS");
              source.registerCorsConfiguration("/**", config);
       
              FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
              bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
              return bean;
          }
      }

      方式三:使用 Spring Security 和 CORS

      如果你的应用程序使用了 Spring Security,你还需要确保 Spring Security 允许 CORS 请求。你可以通过配置 SecurityConfigurerAdapter 来实现:

      java
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.config.annotation.web.builders.HttpSecurity;
      import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.web.servlet.config.annotation.CorsRegistry;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
       
      @Configuration
      @EnableWebSecurity
      public class SecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
       
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .cors()
                  .and()
                  .authorizeRequests()
                  .anyRequest().authenticated()
                  .and()
                  .httpBasic();
          }
       
          @Bean
          public WebMvcConfigurer corsConfigurer() {
              return new WebMvcConfigurer() {
                  @Override
                  public void addCorsMappings(CorsRegistry registry) {
                      registry.addMapping("/api/**")
                              .allowedOrigins("http://example.com", "http://another-example.com")
                              .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                              .allowedHeaders("*")
                              .allowCredentials(true);
                  }
              };
          }
      }

      方式 四:使用 application.properties application.yml,对于简单的 CORS 配置,可以直接在配置文件中设置。

      properties
      # application.properties 示例
      spring.mvc.cors.allowed-origins=http://example.com
      spring.mvc.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
      spring.mvc.cors.allowed-headers=*
      spring.mvc.cors.allow-credentials=true

      yaml

      yaml
      # application.yml 示例
      spring:
        mvc:
          cors:
            allowed-origins: "http://example.com"
            allowed-methods: "GET, POST, PUT, DELETE, OPTIONS"
            allowed-headers: "*"
            allow-credentials: true

注意事项

  • 安全性:不要随意将 allowedOrigins 设置为 "*",除非你确实希望所有域都能访问你的资源。这可能会带来安全风险。
  • 预检请求(Preflight Requests):当 HTTP 请求方法不是简单请求(如 GET、POST),或者包含自定义头部时,浏览器会先发送一个 OPTIONS 请求来检查服务器是否允许真正的请求。确保正确配置这些预检请求。
  • 凭证支持:如果启用了 allowCredentials(true),那么 allowedOrigins 就不能是 "*". 必须明确列出具体的来源域名。
  • 性能考虑:对于大型应用,最好仅对必要的端点启用 CORS,并尽量减少不必要的配置以优化性能。

Spring Cache有几个常用注解?

Spring Cache提供了几个常用的注解,用于在Spring应用程序中声明式地管理缓存。这些注解使得缓存的配置变得简洁明了,允许开发者轻松实现数据的自动缓存、更新和清除,从而优化应用性能,减少不必要的计算和数据访问开销。以下是Spring Cache的几个常用注解:

  1. @EnableCaching:用于在Spring配置类上启用缓存管理功能。这是一个类级别的注解,没有属性。当在配置类上添加了@EnableCaching注解后,Spring就会启动对注解缓存的支持。
  2. @Cacheable:用于声明一个方法的结果是可缓存的。如果缓存中存在相同请求参数的结果,则直接返回缓存中的结果,否则执行该方法,并将结果存入缓存。它支持多个属性,如value或cacheNames(指定缓存名称,可以是单个或多个)、key(指定缓存键的SpEL表达式)、condition(指定缓存的条件SpEL表达式)、unless(指定不缓存的条件SpEL表达式)等。
  3. @CachePut:用于在方法执行后更新缓存。与@Cacheable不同的是,@CachePut每次都会执行方法,并将结果存入缓存,通常用于更新缓存而不改变方法的返回值。它的属性与@Cacheable相同。
  4. @CacheEvict:用于在方法执行后清除缓存。它可以指定清除单个缓存项或所有缓存项,并支持条件清除。value或cacheNames属性指定缓存名称,可以是单个或多个;allEntries属性表示是否清除所有缓存项;condition属性指定清除缓存的条件SpEL表达式。
  5. @Caching:用于组合多个缓存操作,如同时需要缓存数据和删除数据。它包含cacheable、put和evict三个属性,分别用于指定@Cacheable、@CachePut和@CacheEvict注解。
  6. @CacheConfig:用于在类级别提供缓存相关的共享配置。它支持cacheNames(指定类中所有缓存操作的默认缓存名称)、keyGenerator(指定默认的缓存键生成器)、condition(指定类中所有缓存操作的默认条件)等属性。这样,类中的方法就可以使用这些共享配置,而无需在每个方法上都指定相同的配置。

此外,虽然不常用,但还有一些其他注解如**@CacheResult**(非官方注解,用于替代@Cacheable并提供额外的配置选项,如超时时间)等,也可以用于缓存管理。但需要注意的是,这些注解的可用性和具体行为可能因Spring Cache的版本和所使用的缓存技术而有所不同。

SpringBoot 根据配置文件的内容动态地创建Bean?

在 Spring Boot 中,根据配置文件动态创建 Bean 是一种常见的需求,例如基于不同的环境配置或用户输入来实例化特定类型的 Bean。实现这一目标有多种方式,下面介绍几种常用的方法:

  1. 使用 @ConfigurationProperties@Bean

    可以定义一个带有 @ConfigurationProperties 注解的类来绑定配置文件中的属性,并在同一个类中使用 @Bean 方法来动态创建 Bean。

    java
    @ConfigurationProperties(prefix = "myapp.datasource")
    public class DataSourceProperties {
    
        private String url;
        private String username;
        private String password;
    
        // getters and setters
    }
    
    @Configuration
    public class DataSourceConfig {
    
        @Autowired
        private DataSourceProperties dataSourceProperties;
    
        @Bean
        public DataSource dataSource() {
            return DataSourceBuilder.create()
            .url(dataSourceProperties.getUrl())
            .username(dataSourceProperties.getUsername())
            .password(dataSourceProperties.getPassword())
            .build();
        }
    }
  2. 使用 @ConditionalOnProperty 或其他条件注解

    Spring Boot 提供了一系列条件注解(如 @ConditionalOnProperty, @ConditionalOnClass, @ConditionalOnMissingBean 等),可以根据配置文件中的属性值或其他条件来决定是否创建某个 Bean。

    java
    @Configuration
    public class MyFeatureConfig {
    
        @Bean
        @ConditionalOnProperty(name = "myapp.feature.enabled", havingValue = "true", matchIfMissing = false)
      // 只有当 `myapp.feature.enabled=true` 时才会创建 `MyFeature` Bean。  
      public MyFeature myFeature() {
            return new MyFeature();
        }
    }
  3. 使用 FactoryBean 接口

    如果你需要更复杂的逻辑来创建 Bean,可以实现 FactoryBean 接口。这允许你在工厂方法中编写任意代码来确定如何构造 Bean。

    java
    public class MyBeanFactory implements FactoryBean<MyBean> {
    
        private final Environment environment;
    
        @Autowired
        public MyBeanFactory(Environment environment) {
            this.environment = environment;
        }
    
        @Override
        public MyBean getObject() throws Exception {
            // 根据配置文件中的属性动态创建 MyBean 实例
            boolean flag = Boolean.parseBoolean(environment.getProperty("mybean.flag"));
            if (flag) {
                return new MyBeanImpl1();
            } else {
                return new MyBeanImpl2();
            }
        }
    
        @Override
        public Class<?> getObjectType() {
            return MyBean.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }

    然后将 MyBeanFactory 注册为 Bean:

    java
    @Configuration
    public class MyBeanConfig {
    
        @Bean
        public FactoryBean<MyBean> myBeanFactory(Environment environment) {
            return new MyBeanFactory(environment);
        }
    }
  4. 使用 ApplicationListener<EnvironmentPostProcessor> 动态修改 Bean 定义

    如果你想在应用程序启动之前修改 Bean 的定义,可以实现 EnvironmentPostProcessor 接口并在其中添加自定义逻辑。这种方式适用于更高级的场景。

    java
    @Component
    public class DynamicBeanRegistrar implements ApplicationListener<EnvironmentPostProcessor.ApplicationStartupEvent> {
    
        @Override
        public void onApplicationEvent(ApplicationStartupEvent event) {
            ConfigurableApplicationContext context = event.getApplicationContext();
            Environment environment = context.getEnvironment();
    
            // 根据环境变量动态注册 Bean
            if (Boolean.parseBoolean(environment.getProperty("dynamic.bean.enabled"))) {
                context.getBeanFactory().registerSingleton("dynamicBean", new DynamicBean());
            }
        }
    }
  5. 使用 @ImportImportSelector

    通过实现 ImportSelector 接口,可以根据配置文件中的属性选择性地导入某些配置类。然后在配置类中使用 @Import(MyFeatureSelector.class) 来加载它。

    java
    public class MyFeatureSelector implements ImportSelector {
    
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            Environment environment = ((StandardEnvironment) ((StandardAnnotationMetadata) importingClassMetadata).getEnvironment()).getEnvironment();
            if (Boolean.parseBoolean(environment.getProperty("myfeature.enabled"))) {
                return new String[]{"com.example.MyFeatureConfig"};
            }
            return new String[0];
        }
    }

上述方法展示了如何根据配置文件动态创建 Bean 的不同途径。选择哪种方法取决于具体的业务需求和技术背景。对于简单的场景,@ConfigurationProperties 和条件注解可能是最直接的选择;而对于更复杂的需求,则可能需要结合 FactoryBeanEnvironmentPostProcessor 或者 ImportSelector 等工具来实现。

基于 MIT 许可发布