IO

1. 缓存

Spring Framework 支持以透明方式向应用程序添加缓存。 抽象的核心是将缓存应用于方法,从而根据缓存中可用的信息减少执行次数。 缓存逻辑以透明方式应用,不会对调用程序造成任何干扰。 Spring Boot 会自动配置缓存基础设施,只要使用@EnableCaching注解。spring-doc.cadn.net.cn

有关更多详细信息,请查看 Spring Framework 参考的相关部分

简而言之,要将缓存添加到服务的作中,请将相关 Comments 添加到其方法中,如以下示例所示:spring-doc.cadn.net.cn

Java
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

@Component
public class MyMathService {

    @Cacheable("piDecimals")
    public int computePiDecimal(int precision) {
        ...
    }

}
Kotlin
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Component

@Component
class MyMathService {

    @Cacheable("piDecimals")
    fun computePiDecimal(precision: Int): Int {
        ...
    }

}

此示例演示了如何在可能成本高昂的作中使用缓存。 调用computePiDecimal中,抽象在piDecimalscache 匹配i论点。 如果找到条目,则缓存中的内容会立即返回给调用方,并且不会调用该方法。 否则,将调用该方法,并在返回值之前更新缓存。spring-doc.cadn.net.cn

您还可以使用标准 JSR-107 (JCache) 注释(例如@CacheResult) 透明地显示。 但是,我们强烈建议您不要混合和匹配 Spring Cache 和 JCache 注释。

如果不添加任何特定的缓存库, Spring Boot 会自动配置一个简单的提供程序,该提供程序在内存中使用并发映射。 当需要缓存时(例如piDecimals在前面的示例中),此提供程序会为您创建它。 简单提供程序并不真正推荐用于生产用途,但它非常适合入门并确保您了解这些功能。 当您决定要使用的缓存提供程序时,请务必阅读其文档以了解如何配置应用程序使用的缓存。 几乎所有提供程序都要求您显式配置在应用程序中使用的每个缓存。 有些提供了自定义由spring.cache.cache-names财产。spring-doc.cadn.net.cn

还可以透明地从缓存中更新逐出数据。

1.1. 支持的缓存提供程序

缓存抽象不提供实际的存储,并且依赖于由org.springframework.cache.Cacheorg.springframework.cache.CacheManager接口。spring-doc.cadn.net.cn

如果您尚未定义CacheManagerCacheResolvercacheResolver(参见CachingConfigurer),Spring Boot 会尝试检测以下提供程序(按指示的顺序):spring-doc.cadn.net.cn

如果CacheManager由 Spring Boot 自动配置,则可以通过将spring.cache.type财产。 如果需要在某些环境(例如测试)中使用无作缓存,请使用此属性。
使用spring-boot-starter-cache“Starter” 快速添加基本的缓存依赖项。 首发球员带来spring-context-support. 如果手动添加依赖项,则必须包含spring-context-support以使用 JCache 或 Caffeine 支持。

如果CacheManager由 Spring Boot 自动配置,则可以通过公开实现CacheManagerCustomizer接口。 下面的示例设置一个标志来表示null值不应向下传递到底层 Map:spring-doc.cadn.net.cn

Java
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCacheManagerConfiguration {

    @Bean
    public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
        return (cacheManager) -> cacheManager.setAllowNullValues(false);
    }

}
Kotlin
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer
import org.springframework.cache.concurrent.ConcurrentMapCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyCacheManagerConfiguration {

    @Bean
    fun cacheManagerCustomizer(): CacheManagerCustomizer<ConcurrentMapCacheManager> {
        return CacheManagerCustomizer { cacheManager ->
            cacheManager.isAllowNullValues = false
        }
    }

}
在前面的示例中,自动配置的ConcurrentMapCacheManager是意料之中的。 如果不是这种情况(您提供了自己的配置或自动配置了其他缓存提供程序),则根本不会调用定制器。 您可以根据需要拥有任意数量的定制器,也可以使用@OrderOrdered.

1.1.1. 泛型

如果上下文定义了至少一个org.springframework.cache.Cache豆。 一个CacheManager将创建该类型的所有 Wrapping 。spring-doc.cadn.net.cn

1.1.2. JCache (JSR-107)

JCache 是通过存在javax.cache.spi.CachingProvider在类路径上(即,类路径上存在符合 JSR-107 的缓存库),并且JCacheCacheManagerspring-boot-starter-cache“Starters”。 可以使用各种兼容的库,并且 Spring Boot 为 Ehcache 3、Hazelcast 和 Infinispan 提供依赖项管理。 也可以添加任何其他兼容的库。spring-doc.cadn.net.cn

可能会存在多个提供程序,在这种情况下,必须显式指定提供程序。 即使 JSR-107 标准没有强制执行定义配置文件位置的标准化方法, Spring Boot 也会尽力适应使用实现细节设置缓存,如以下示例所示:spring-doc.cadn.net.cn

性能
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.example.MyCachingProvider
spring.cache.jcache.config=classpath:example.xml
Yaml
# Only necessary if more than one provider is present
spring:
  cache:
    jcache:
      provider: "com.example.MyCachingProvider"
      config: "classpath:example.xml"
当缓存库同时提供本机实现和 JSR-107 支持时, Spring Boot 更喜欢 JSR-107 支持,因此,如果你切换到不同的 JSR-107 实现,则可以使用相同的功能。
Spring Boot 具有对 Hazelcast 的一般支持。 如果单个HazelcastInstance可用,它会自动重新用于CacheManager以及,除非spring.cache.jcache.config属性。

有两种方法可以自定义底层javax.cache.cacheManager:spring-doc.cadn.net.cn

  • 可以在启动时通过设置spring.cache.cache-names财产。 如果自定义javax.cache.configuration.Configurationbean 的定义,则用于自定义它们。spring-doc.cadn.net.cn

  • org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizerbean 是使用CacheManager进行完全自定义。spring-doc.cadn.net.cn

如果标准的javax.cache.CacheManagerbean 时,它会自动包装在org.springframework.cache.CacheManager抽象期望的实现。 不会对其应用进一步的自定义。

1.1.3. 黑泽尔广播

Spring Boot 具有对 Hazelcast 的一般支持。 如果HazelcastInstance已自动配置并且com.hazelcast:hazelcast-spring位于 Classpath 上,它会自动包装在CacheManager.spring-doc.cadn.net.cn

Hazelcast 可以用作符合 JCache 的缓存或用作 SpringCacheManagercompliant 缓存。 设置spring.cache.typehazelcast,Spring Boot 将使用CacheManager基于实施。 如果要将 Hazelcast 用作符合 JCache 的缓存,请将spring.cache.typejcache. 如果您有多个符合 JCache 的缓存提供程序并希望强制使用 Hazelcast,则必须显式设置 JCache 提供程序

1.1.4. Infinispan

Infinispan 没有默认的配置文件位置,因此必须显式指定它。 否则,将使用默认引导程序。spring-doc.cadn.net.cn

性能
spring.cache.infinispan.config=infinispan.xml
Yaml
spring:
  cache:
    infinispan:
      config: "infinispan.xml"

可以在启动时通过设置spring.cache.cache-names财产。 如果自定义ConfigurationBuilderbean,它用于自定义缓存。spring-doc.cadn.net.cn

为了兼容 Spring Boot 的 Jakarta EE 9 基线,Infinispan 的-jakarta必须使用 modules。 对于每个具有-jakartavariant 中,必须使用 variant 代替 standard 模块。 例如infinispan-core-jakartainfinispan-commons-jakarta必须代替infinispan-coreinfinispan-commons分别。spring-doc.cadn.net.cn

1.1.5. Couchbase

如果 Spring Data Couchbase 可用并且配置了 Couchbase,则CouchbaseCacheManager是自动配置的。 可以通过将spring.cache.cache-names属性和缓存默认值可以使用spring.cache.couchbase.*性能。 例如,以下配置创建cache1cache2条目过期时间为 10 分钟的缓存:spring-doc.cadn.net.cn

性能
spring.cache.cache-names=cache1,cache2
spring.cache.couchbase.expiration=10m
Yaml
spring:
  cache:
    cache-names: "cache1,cache2"
    couchbase:
      expiration: "10m"

如果您需要对配置进行更多控制,请考虑注册CouchbaseCacheManagerBuilderCustomizer豆。 以下示例显示了一个定制器,该定制器为cache1cache2:spring-doc.cadn.net.cn

Java
import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyCouchbaseCacheManagerConfiguration {

    @Bean
    public CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() {
        return (builder) -> builder
                .withCacheConfiguration("cache1", CouchbaseCacheConfiguration
                        .defaultCacheConfig().entryExpiry(Duration.ofSeconds(10)))
                .withCacheConfiguration("cache2", CouchbaseCacheConfiguration
                        .defaultCacheConfig().entryExpiry(Duration.ofMinutes(1)));

    }

}
Kotlin
import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class MyCouchbaseCacheManagerConfiguration {

    @Bean
    fun myCouchbaseCacheManagerBuilderCustomizer(): CouchbaseCacheManagerBuilderCustomizer {
        return CouchbaseCacheManagerBuilderCustomizer { builder ->
            builder
                .withCacheConfiguration(
                    "cache1", CouchbaseCacheConfiguration
                        .defaultCacheConfig().entryExpiry(Duration.ofSeconds(10))
                )
                .withCacheConfiguration(
                    "cache2", CouchbaseCacheConfiguration
                        .defaultCacheConfig().entryExpiry(Duration.ofMinutes(1))
                )
        }
    }

}

1.1.6. Redis

如果 Redis 可用且已配置,则RedisCacheManager是自动配置的。 可以通过将spring.cache.cache-names属性和缓存默认值可以使用spring.cache.redis.*性能。 例如,以下配置创建cache1cache2生存时间为 10 分钟的缓存:spring-doc.cadn.net.cn

性能
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=10m
Yaml
spring:
  cache:
    cache-names: "cache1,cache2"
    redis:
      time-to-live: "10m"
默认情况下,会添加键前缀,这样,如果两个单独的缓存使用相同的键,Redis 没有重叠的键,也不会返回无效值。 如果您创建自己的RedisCacheManager.
您可以通过添加RedisCacheConfiguration @Bean你自己的。 如果您需要自定义默认序列化策略,这可能很有用。

如果您需要对配置进行更多控制,请考虑注册RedisCacheManagerBuilderCustomizer豆。 以下示例显示了一个定制器,该定制器配置了特定的生存时间cache1cache2:spring-doc.cadn.net.cn

Java
import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyRedisCacheManagerConfiguration {

    @Bean
    public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
        return (builder) -> builder
                .withCacheConfiguration("cache1", RedisCacheConfiguration
                        .defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
                .withCacheConfiguration("cache2", RedisCacheConfiguration
                        .defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));

    }

}
Kotlin
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class MyRedisCacheManagerConfiguration {

    @Bean
    fun myRedisCacheManagerBuilderCustomizer(): RedisCacheManagerBuilderCustomizer {
        return RedisCacheManagerBuilderCustomizer { builder ->
            builder
                .withCacheConfiguration(
                    "cache1", RedisCacheConfiguration
                        .defaultCacheConfig().entryTtl(Duration.ofSeconds(10))
                )
                .withCacheConfiguration(
                    "cache2", RedisCacheConfiguration
                        .defaultCacheConfig().entryTtl(Duration.ofMinutes(1))
                )
        }
    }

}

1.1.7. 咖啡因

Caffeine 是 Guava 缓存的 Java 8 重写,它取代了对 Guava 的支持。 如果存在咖啡因,则CaffeineCacheManager(由spring-boot-starter-cache“Starter”) 是自动配置的。 可以在启动时通过设置spring.cache.cache-names属性,并且可以由以下选项之一(按指示的顺序)进行自定义:spring-doc.cadn.net.cn

  1. spring.cache.caffeine.specspring-doc.cadn.net.cn

  2. 一个com.github.benmanes.caffeine.cache.CaffeineSpecbean 定义spring-doc.cadn.net.cn

  3. 一个com.github.benmanes.caffeine.cache.Caffeinebean 定义spring-doc.cadn.net.cn

例如,以下配置创建cache1cache2最大大小为 500 且生存时间为 10 分钟的缓存spring-doc.cadn.net.cn

性能
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
Yaml
spring:
  cache:
    cache-names: "cache1,cache2"
    caffeine:
      spec: "maximumSize=500,expireAfterAccess=600s"

如果com.github.benmanes.caffeine.cache.CacheLoaderbean 时,它会自动关联到CaffeineCacheManager. 由于CacheLoader将与缓存管理器管理的所有缓存相关联,则必须将其定义为CacheLoader<Object, Object>. auto-configuration 会忽略任何其他泛型类型。spring-doc.cadn.net.cn

1.1.8. 缓存2k

Cache2k 是内存中的缓存。 如果存在 Cache2k Spring 集成,则SpringCache2kCacheManager是自动配置的。spring-doc.cadn.net.cn

可以在启动时通过设置spring.cache.cache-names财产。 缓存默认值可以使用Cache2kBuilderCustomizer豆。 以下示例显示了一个定制器,该定制器将缓存的容量配置为 200 个条目,过期时间为 5 分钟:spring-doc.cadn.net.cn

Java
import java.util.concurrent.TimeUnit;

import org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCache2kDefaultsConfiguration {

    @Bean
    public Cache2kBuilderCustomizer myCache2kDefaultsCustomizer() {
        return (builder) -> builder.entryCapacity(200)
                .expireAfterWrite(5, TimeUnit.MINUTES);
    }

}
Kotlin
import org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.TimeUnit

@Configuration(proxyBeanMethods = false)
class MyCache2kDefaultsConfiguration {

    @Bean
    fun myCache2kDefaultsCustomizer(): Cache2kBuilderCustomizer {
        return Cache2kBuilderCustomizer { builder ->
            builder.entryCapacity(200)
                .expireAfterWrite(5, TimeUnit.MINUTES)
        }
    }
}

1.1.9. 简单

如果找不到其他提供程序,则使用ConcurrentHashMap作为缓存存储的配置。 如果您的应用程序中不存在缓存库,则这是默认值。 默认情况下,缓存是根据需要创建的,但您可以通过设置cache-names财产。 例如,如果您只想cache1cache2caches,将cache-names属性,如下所示:spring-doc.cadn.net.cn

性能
spring.cache.cache-names=cache1,cache2
Yaml
spring:
  cache:
    cache-names: "cache1,cache2"

如果您这样做,并且您的应用程序使用未列出的缓存,则它会在运行时需要缓存时失败,但在启动时不会失败。 这类似于使用未声明的缓存时“真实”缓存提供程序的行为方式。spring-doc.cadn.net.cn

1.1.10. 无

什么时候@EnableCaching,则还需要合适的缓存配置。 如果您有一个自定义的CacheManager,请考虑在单独的@Configuration类,以便您可以根据需要覆盖它。 None 使用在测试中有用的 no-op 实现,而 slice 测试默认通过@AutoConfigureCache.spring-doc.cadn.net.cn

如果需要在特定环境中使用 no-op 缓存而不是自动配置的缓存管理器,请将缓存类型设置为none,如以下示例所示:spring-doc.cadn.net.cn

性能
spring.cache.type=none
Yaml
spring:
  cache:
    type: "none"

2. Hazelcast

如果 Hazelcast 位于 Classpath 上并且找到合适的配置,则 Spring Boot 会自动配置一个HazelcastInstance,您可以将其注入到您的应用程序中。spring-doc.cadn.net.cn

Spring Boot 首先尝试通过检查以下配置选项来创建客户端:spring-doc.cadn.net.cn

如果无法创建 Client 端,则 Spring Boot 将尝试配置嵌入式服务器。 如果您定义了com.hazelcast.config.Configbean,Spring Boot 会使用它。 如果您的配置定义了实例名称,则 Spring Boot 会尝试查找现有实例,而不是创建新实例。spring-doc.cadn.net.cn

您还可以指定要通过配置使用的 Hazelcast 配置文件,如以下示例所示:spring-doc.cadn.net.cn

性能
spring.hazelcast.config=classpath:config/my-hazelcast.xml
Yaml
spring:
  hazelcast:
    config: "classpath:config/my-hazelcast.xml"

否则, Spring Boot 会尝试从默认位置查找 Hazelcast 配置:hazelcast.xml在工作目录或 Classpath 的根目录中,或者相同位置的 YAML 对应项。 我们还会检查hazelcast.configsystem 属性。 有关更多详细信息,请参阅 Hazelcast 文档spring-doc.cadn.net.cn

默认情况下,@SpringAware在 Hazelcast 组件上。 这ManagementContext可以通过声明HazelcastConfigCustomizer带有@Order高于零。
Spring Boot 还具有对 Hazelcast 的显式缓存支持。 如果启用了缓存,则HazelcastInstance会自动包装在CacheManager实现。

3. Quartz 调度器

Spring Boot 为使用 Quartz 调度程序提供了多种便利,包括spring-boot-starter-quartz“Starters”。 如果 Quartz 可用,则Scheduler是自动配置的(通过SchedulerFactoryBeanabstraction)。spring-doc.cadn.net.cn

以下类型的 bean 将被自动选取并与Scheduler:spring-doc.cadn.net.cn

默认情况下,内存中的JobStore被使用。 但是,如果DataSourcebean 在您的应用程序中可用,并且如果spring.quartz.job-store-type属性,如以下示例所示:spring-doc.cadn.net.cn

性能
spring.quartz.job-store-type=jdbc
Yaml
spring:
  quartz:
    job-store-type: "jdbc"

使用 JDBC 存储时,可以在启动时初始化架构,如以下示例所示:spring-doc.cadn.net.cn

性能
spring.quartz.jdbc.initialize-schema=always
Yaml
spring:
  quartz:
    jdbc:
      initialize-schema: "always"
默认情况下,使用 Quartz 库提供的标准脚本检测和初始化数据库。 这些脚本会删除现有表,并在每次重启时删除所有触发器。 也可以通过设置spring.quartz.jdbc.schema财产。

要让 Quartz 使用DataSource除了应用程序的 mainDataSource,声明一个DataSourcebean,为其@Beanmethod 替换为@QuartzDataSource. 这样做可以确保特定于 Quartz 的DataSourceSchedulerFactoryBean以及 schema 初始化。 同样,要让 Quartz 使用TransactionManager除了应用程序的 mainTransactionManager声明一个TransactionManagerbean,为其@Beanmethod 替换为@QuartzTransactionManager.spring-doc.cadn.net.cn

默认情况下,通过配置创建的作业不会覆盖已从持久性作业存储中读取的已注册作业。 要启用覆盖现有作业定义,请将spring.quartz.overwrite-existing-jobs财产。spring-doc.cadn.net.cn

可以使用 Quartz Scheduler 配置进行自定义spring.quartzproperties 和SchedulerFactoryBeanCustomizerbean,它允许以编程方式SchedulerFactoryBean定制。 高级 Quartz 配置属性可使用spring.quartz.properties.*.spring-doc.cadn.net.cn

特别是,Executorbean 与调度器无关,因为 Quartz 提供了一种通过spring.quartz.properties. 如果需要自定义任务执行程序,请考虑实现SchedulerFactoryBeanCustomizer.

Job 可以定义 setter 来注入数据映射属性。 常规 bean 也可以以类似的方式注入,如以下示例所示:spring-doc.cadn.net.cn

Java
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import org.springframework.scheduling.quartz.QuartzJobBean;

public class MySampleJob extends QuartzJobBean {

    // fields ...

    private MyService myService;

    private String name;

    // Inject "MyService" bean
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    // Inject the "name" job data property
    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        this.myService.someMethod(context.getFireTime(), this.name);
    }

}
Kotlin
import org.quartz.JobExecutionContext
import org.springframework.scheduling.quartz.QuartzJobBean

class MySampleJob : QuartzJobBean() {

    // fields ...

    private var myService: MyService? = null

    private var name: String? = null

    // Inject "MyService" bean
    fun setMyService(myService: MyService?) {
        this.myService = myService
    }

    // Inject the "name" job data property
    fun setName(name: String?) {
        this.name = name
    }

    override fun executeInternal(context: JobExecutionContext) {
        myService!!.someMethod(context.fireTime, name)
    }

}

4. 发送电子邮件

Spring Framework 通过使用JavaMailSender接口,Spring Boot 为其提供自动配置以及 starter 模块。spring-doc.cadn.net.cn

有关如何使用JavaMailSender.

如果spring.mail.host和相关库(由spring-boot-starter-mail) 可用,则默认JavaMailSender如果不存在,则创建。 发送者可以通过spring.mailNamespace。 看MailProperties了解更多详情。spring-doc.cadn.net.cn

特别是,某些默认超时值是无限的,您可能希望更改该值以避免线程被无响应的邮件服务器阻止,如以下示例所示:spring-doc.cadn.net.cn

性能
spring.mail.properties[mail.smtp.connectiontimeout]=5000
spring.mail.properties[mail.smtp.timeout]=3000
spring.mail.properties[mail.smtp.writetimeout]=5000
Yaml
spring:
  mail:
    properties:
      "[mail.smtp.connectiontimeout]": 5000
      "[mail.smtp.timeout]": 3000
      "[mail.smtp.writetimeout]": 5000

还可以配置JavaMailSender与现有的Session来自 JNDI:spring-doc.cadn.net.cn

性能
spring.mail.jndi-name=mail/Session
Yaml
spring:
  mail:
    jndi-name: "mail/Session"

jndi-name设置,则它优先于所有其他与 Session 相关的设置。spring-doc.cadn.net.cn

5. 验证

只要 JSR-303 实现(例如 Hibernate 验证器)在 Classpath 上,Bean Validation 1.1 支持的方法验证功能就会自动启用。 这允许 bean 方法使用jakarta.validation对其参数和/或返回值的约束。 具有此类 Comments 方法的目标类需要使用@Validatedannotation 的 Comments,以便搜索其方法的内联约束 Comments。spring-doc.cadn.net.cn

例如,以下服务触发第一个参数的验证,确保其大小介于 8 和 10 之间:spring-doc.cadn.net.cn

Java
import jakarta.validation.constraints.Size;

import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

@Service
@Validated
public class MyBean {

    public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, Author author) {
        return ...
    }

}
Kotlin
import jakarta.validation.constraints.Size
import org.springframework.stereotype.Service
import org.springframework.validation.annotation.Validated

@Service
@Validated
class MyBean {

    fun findByCodeAndAuthor(code: @Size(min = 8, max = 10) String?, author: Author?): Archive? {
        return null
    }

}

应用程序的MessageSource在解析时使用{parameters}在约束消息中。 这允许您使用应用程序的messages.properties文件以获取 Bean 验证消息。 解析参数后,将使用 Bean Validation 的默认插值器完成消息插值。spring-doc.cadn.net.cn

要自定义Configuration用于构建ValidatorFactory中,定义一个ValidationConfigurationCustomizer豆。 定义多个定制器 bean 时,将根据它们的@Orderannotation 或Ordered实现。spring-doc.cadn.net.cn

6. 调用 REST 服务

如果您的应用程序调用远程 REST 服务,Spring Boot 使用RestTemplateWebClient.spring-doc.cadn.net.cn

6.1. RestTemplate

如果需要从应用程序调用远程 REST 服务,可以使用 Spring Framework 的RestTemplate类。 因为RestTemplate实例在使用之前通常需要进行自定义,Spring Boot 不提供任何单一的自动配置RestTemplate豆。 但是,它会自动配置RestTemplateBuilder,可用于创建RestTemplate实例。 自动配置的RestTemplateBuilder确保 SensibleHttpMessageConverters应用于RestTemplate实例。spring-doc.cadn.net.cn

以下代码显示了一个典型的示例:spring-doc.cadn.net.cn

Java
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class MyService {

    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    public Details someRestCall(String name) {
        return this.restTemplate.getForObject("/{name}/details", Details.class, name);
    }

}
Kotlin
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate

@Service
class MyService(restTemplateBuilder: RestTemplateBuilder) {

    private val restTemplate: RestTemplate

    init {
        restTemplate = restTemplateBuilder.build()
    }

    fun someRestCall(name: String): Details {
        return restTemplate.getForObject("/{name}/details", Details::class.java, name)!!
    }

}

RestTemplateBuilder包含许多有用的方法,可用于快速配置RestTemplate. 例如,要添加 BASIC 身份验证支持,您可以使用builder.basicAuthentication("user", "password").build().spring-doc.cadn.net.cn

6.1.1. RestTemplate HTTP 客户端

Spring Boot 将自动检测要使用的 HTTP 客户端RestTemplate取决于应用程序 Classpath 上可用的库。 按优先顺序,支持以下客户端:spring-doc.cadn.net.cn

  1. Apache HttpClientspring-doc.cadn.net.cn

  2. OkHttpspring-doc.cadn.net.cn

  3. 简单 JDK 客户端 (HttpURLConnection)spring-doc.cadn.net.cn

如果 Classpath 上有多个 Client 端可用,则将使用最首选的 Client 端。spring-doc.cadn.net.cn

6.1.2. RestTemplate 自定义

有三种主要方法RestTemplate自定义,具体取决于您希望自定义应用的范围。spring-doc.cadn.net.cn

要使任何自定义的范围尽可能窄,请注入自动配置的RestTemplateBuilder然后根据需要调用其方法。 每个方法调用都会返回一个新的RestTemplateBuilder实例,因此自定义项仅影响 Builder 的这种使用。spring-doc.cadn.net.cn

要进行应用程序范围的增材自定义,请使用RestTemplateCustomizer豆。 所有此类 bean 都会自动注册到自动配置的RestTemplateBuilder并应用于使用它构建的任何模板。spring-doc.cadn.net.cn

以下示例显示了一个定制器,该定制器为除192.168.0.5:spring-doc.cadn.net.cn

Java
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;

import org.springframework.boot.web.client.RestTemplateCustomizer;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class MyRestTemplateCustomizer implements RestTemplateCustomizer {

    @Override
    public void customize(RestTemplate restTemplate) {
        HttpRoutePlanner routePlanner = new CustomRoutePlanner(new HttpHost("proxy.example.com"));
        HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build();
        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    }

    static class CustomRoutePlanner extends DefaultProxyRoutePlanner {

        CustomRoutePlanner(HttpHost proxy) {
            super(proxy);
        }

        @Override
        protected HttpHost determineProxy(HttpHost target, HttpContext context) throws HttpException {
            if (target.getHostName().equals("192.168.0.5")) {
                return null;
            }
            return super.determineProxy(target, context);
        }

    }

}
Kotlin
import org.apache.hc.client5.http.classic.HttpClient
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner
import org.apache.hc.client5.http.routing.HttpRoutePlanner
import org.apache.hc.core5.http.HttpException
import org.apache.hc.core5.http.HttpHost
import org.apache.hc.core5.http.protocol.HttpContext
import org.springframework.boot.web.client.RestTemplateCustomizer
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate

class MyRestTemplateCustomizer : RestTemplateCustomizer {

    override fun customize(restTemplate: RestTemplate) {
        val routePlanner: HttpRoutePlanner = CustomRoutePlanner(HttpHost("proxy.example.com"))
        val httpClient: HttpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build()
        restTemplate.requestFactory = HttpComponentsClientHttpRequestFactory(httpClient)
    }

    internal class CustomRoutePlanner(proxy: HttpHost?) : DefaultProxyRoutePlanner(proxy) {

        @Throws(HttpException::class)
        public override fun determineProxy(target: HttpHost, context: HttpContext): HttpHost? {
            if (target.hostName == "192.168.0.5") {
                return null
            }
            return  super.determineProxy(target, context)
        }

    }

}

最后,您可以定义自己的RestTemplateBuilder豆。 这样做将替换自动配置的生成器。 如果你想要任何RestTemplateCustomizerbean 应用于您的自定义构建器,就像自动配置所做的那样,使用RestTemplateBuilderConfigurer. 以下示例公开了RestTemplateBuilder这与 Spring Boot 的自动配置将执行的作相匹配,只是还指定了自定义连接和读取超时:spring-doc.cadn.net.cn

Java
import java.time.Duration;

import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyRestTemplateBuilderConfiguration {

    @Bean
    public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {
        return configurer.configure(new RestTemplateBuilder())
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(2));
    }

}
Kotlin
import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class MyRestTemplateBuilderConfiguration {

    @Bean
    fun restTemplateBuilder(configurer: RestTemplateBuilderConfigurer): RestTemplateBuilder {
        return configurer.configure(RestTemplateBuilder()).setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(2))
    }

}

最极端(也很少使用)的选项是创建自己的RestTemplateBuilderBean 的 Bean 中。 除了替换自动配置的构建器外,这还可以防止任何RestTemplateCustomizer豆子被使用。spring-doc.cadn.net.cn

6.1.3. RestTemplate SSL 支持

如果您需要在RestTemplate中,您可以将 SSL 捆绑包应用于RestTemplateBuilder如以下示例所示:spring-doc.cadn.net.cn

Java
import org.springframework.boot.docs.io.restclient.resttemplate.Details;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class MyService {

    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
        this.restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build();
    }

    public Details someRestCall(String name) {
        return this.restTemplate.getForObject("/{name}/details", Details.class, name);
    }

}
Kotlin
import org.springframework.boot.docs.io.restclient.resttemplate.Details
import org.springframework.boot.ssl.SslBundles
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate

@Service
class MyService(restTemplateBuilder: RestTemplateBuilder, sslBundles: SslBundles) {

    private val restTemplate: RestTemplate

    init {
        restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build()
    }

    fun someRestCall(name: String): Details {
        return restTemplate.getForObject("/{name}/details", Details::class.java, name)!!
    }

}

6.2. Web客户端

如果你的 classpath 中有 Spring WebFlux,你也可以选择使用WebClient调用远程 REST 服务。 与RestTemplate,这个客户端感觉更实用,并且完全被动。 您可以详细了解WebClientSpring Framework 文档的 dedicated 部分spring-doc.cadn.net.cn

Spring Boot 创建并预配置一个WebClient.Builder给你的。 强烈建议将它注入到您的组件中,并使用它来创建WebClient实例。 Spring Boot 正在配置该构建器以共享 HTTP 资源,以与服务器相同的方式反映编解码器设置(参见 WebFlux HTTP 编解码器自动配置)等等。spring-doc.cadn.net.cn

以下代码显示了一个典型的示例:spring-doc.cadn.net.cn

Java
import reactor.core.publisher.Mono;

import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
public class MyService {

    private final WebClient webClient;

    public MyService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("https://example.org").build();
    }

    public Mono<Details> someRestCall(String name) {
        return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
    }

}
Kotlin
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono

@Service
class MyService(webClientBuilder: WebClient.Builder) {

    private val webClient: WebClient

    init {
        webClient = webClientBuilder.baseUrl("https://example.org").build()
    }

    fun someRestCall(name: String?): Mono<Details> {
        return webClient.get().uri("/{name}/details", name)
                .retrieve().bodyToMono(Details::class.java)
    }

}

6.2.1. WebClient 运行时

Spring Boot 将自动检测哪个ClientHttpConnector用于驾驶WebClient取决于应用程序 Classpath 上可用的库。 按优先顺序,支持以下客户端:spring-doc.cadn.net.cn

  1. Reactor Nettyspring-doc.cadn.net.cn

  2. Jetty RS 客户端spring-doc.cadn.net.cn

  3. Apache HttpClientspring-doc.cadn.net.cn

  4. JDK HttpClientspring-doc.cadn.net.cn

如果 Classpath 上有多个 Client 端可用,则将使用最首选的 Client 端。spring-doc.cadn.net.cn

spring-boot-starter-webfluxStarter 依赖于io.projectreactor.netty:reactor-netty默认情况下,它同时带来 server 和 client 实现。 如果您选择使用 Jetty 作为反应式服务器,则应添加对 Jetty 反应式 HTTP 客户端库的依赖项。org.eclipse.jetty:jetty-reactive-httpclient. 对服务器和客户端使用相同的技术有其优势,因为它会自动在客户端和服务器之间共享 HTTP 资源。spring-doc.cadn.net.cn

开发人员可以通过提供自定义ReactorResourceFactoryJettyResourceFactorybean - 这将应用于客户端和服务器。spring-doc.cadn.net.cn

如果您希望为客户端覆盖该选择,您可以定义自己的ClientHttpConnectorbean 并完全控制客户端配置。spring-doc.cadn.net.cn

6.2.2. WebClient 自定义

有三种主要方法WebClient自定义,具体取决于您希望自定义应用的范围。spring-doc.cadn.net.cn

要使任何自定义的范围尽可能窄,请注入自动配置的WebClient.Builder然后根据需要调用其方法。WebClient.Builder实例是有状态的:生成器上的任何更改都会反映在随后使用它创建的所有客户端中。 如果要使用同一个构建器创建多个客户端,还可以考虑使用WebClient.Builder other = builder.clone();.spring-doc.cadn.net.cn

要对所有应用程序进行 Additive 自定义WebClient.Builder实例中,你可以声明WebClientCustomizerbeans 并将WebClient.Builder注射点局部。spring-doc.cadn.net.cn

最后,您可以回退到原始 API 并使用WebClient.create(). 在这种情况下,没有自动配置或WebClientCustomizerspring-doc.cadn.net.cn

6.2.3. WebClient SSL 支持

如果您需要在ClientHttpConnectorWebClient,您可以注入WebClientSsl实例,该实例可以与构建器的apply方法。spring-doc.cadn.net.cn

WebClientSsl接口提供对您在application.propertiesapplication.yaml文件。spring-doc.cadn.net.cn

以下代码显示了一个典型的示例:spring-doc.cadn.net.cn

Java
import reactor.core.publisher.Mono;

import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
public class MyService {

    private final WebClient webClient;

    public MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {
        this.webClient = webClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
    }

    public Mono<Details> someRestCall(String name) {
        return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
    }

}
Kotlin
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono

@Service
class MyService(webClientBuilder: WebClient.Builder, ssl: WebClientSsl) {

    private val webClient: WebClient

    init {
        webClient = webClientBuilder.baseUrl("https://example.org")
                .apply(ssl.fromBundle("mybundle")).build()
    }

    fun someRestCall(name: String?): Mono<Details> {
        return webClient.get().uri("/{name}/details", name)
                .retrieve().bodyToMono(Details::class.java)
    }

}

7. Web 服务

Spring Boot 提供了 Web 服务自动配置,因此您所要做的就是定义您的Endpoints.spring-doc.cadn.net.cn

Spring Web 服务功能可以通过spring-boot-starter-webservices模块。spring-doc.cadn.net.cn

SimpleWsdl11DefinitionSimpleXsdSchema可以分别为 WSDL 和 XSD 自动创建 bean。 为此,请配置其位置,如以下示例所示:spring-doc.cadn.net.cn

性能
spring.webservices.wsdl-locations=classpath:/wsdl
Yaml
spring:
  webservices:
    wsdl-locations: "classpath:/wsdl"

7.1. 使用 WebServiceTemplate 调用 Web 服务

如果需要从应用程序调用远程 Web 服务,可以使用WebServiceTemplate类。 因为WebServiceTemplate实例在使用之前通常需要进行自定义,Spring Boot 不提供任何单一的自动配置WebServiceTemplate豆。 但是,它会自动配置WebServiceTemplateBuilder,可用于创建WebServiceTemplate实例。spring-doc.cadn.net.cn

以下代码显示了一个典型的示例:spring-doc.cadn.net.cn

Java
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.client.core.SoapActionCallback;

@Service
public class MyService {

    private final WebServiceTemplate webServiceTemplate;

    public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {
        this.webServiceTemplate = webServiceTemplateBuilder.build();
    }

    public SomeResponse someWsCall(SomeRequest detailsReq) {
        return (SomeResponse) this.webServiceTemplate.marshalSendAndReceive(detailsReq,
                new SoapActionCallback("https://ws.example.com/action"));
    }

}
Kotlin
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.ws.client.core.WebServiceTemplate
import org.springframework.ws.soap.client.core.SoapActionCallback

@Service
class MyService(webServiceTemplateBuilder: WebServiceTemplateBuilder) {

    private val webServiceTemplate: WebServiceTemplate

    init {
        webServiceTemplate = webServiceTemplateBuilder.build()
    }

    fun someWsCall(detailsReq: SomeRequest?): SomeResponse {
        return webServiceTemplate.marshalSendAndReceive(
            detailsReq,
            SoapActionCallback("https://ws.example.com/action")
        ) as SomeResponse
    }

}

默认情况下,WebServiceTemplateBuilder检测合适的基于 HTTP 的WebServiceMessageSender使用 Classpath 上可用的 HTTP 客户端库。 您还可以自定义读取和连接超时,如下所示:spring-doc.cadn.net.cn

Java
import java.time.Duration;

import org.springframework.boot.webservices.client.HttpWebServiceMessageSenderBuilder;
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;

@Configuration(proxyBeanMethods = false)
public class MyWebServiceTemplateConfiguration {

    @Bean
    public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
        WebServiceMessageSender sender = new HttpWebServiceMessageSenderBuilder()
                .setConnectTimeout(Duration.ofSeconds(5))
                .setReadTimeout(Duration.ofSeconds(2))
                .build();
        return builder.messageSenders(sender).build();
    }

}
Kotlin
import org.springframework.boot.webservices.client.HttpWebServiceMessageSenderBuilder
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.ws.client.core.WebServiceTemplate
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class MyWebServiceTemplateConfiguration {

    @Bean
    fun webServiceTemplate(builder: WebServiceTemplateBuilder): WebServiceTemplate {
        val sender = HttpWebServiceMessageSenderBuilder()
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(2))
            .build()
        return builder.messageSenders(sender).build()
    }

}

8. 使用 JTA 进行分布式事务

Spring Boot 通过使用从 JNDI 检索的事务管理器来支持跨多个 XA 资源的分布式 JTA 事务。spring-doc.cadn.net.cn

当检测到 JTA 环境时, Spring 的JtaTransactionManager用于管理事务。 自动配置的 JMS、DataSource 和 JPA bean 已升级以支持 XA 事务。 您可以使用标准的 Spring 惯用语,例如@Transactional参与分布式事务。 如果您在 JTA 环境中,并且仍希望使用本地事务,则可以设置spring.jta.enabledproperty 设置为false以禁用 JTA 自动配置。spring-doc.cadn.net.cn

8.1. 使用 Jakarta EE Managed Transaction Manager

如果您将 Spring Boot 应用程序打包为warear文件并将其部署到 Jakarta EE 应用服务器,则可以使用应用服务器的内置事务管理器。 Spring Boot 尝试通过查看常见的 JNDI 位置(java:comp/UserTransaction,java:comp/TransactionManager等)。 使用应用程序服务器提供的事务服务时,您通常还希望确保所有资源都由服务器管理并通过 JNDI 公开。 Spring Boot 尝试通过查找ConnectionFactory在 JNDI 路径 (java:/JmsXAjava:/XAConnectionFactory),并且您可以使用spring.datasource.jndi-name财产要配置DataSource.spring-doc.cadn.net.cn

8.2. 混合 XA 和非 XA JMS 连接

使用 JTA 时,主 JMSConnectionFactorybean 是 XA 感知的,并参与分布式事务。 您可以注入到 bean 中,而无需使用任何@Qualifier:spring-doc.cadn.net.cn

Java
public MyBean(ConnectionFactory connectionFactory) {
    // ...
}
Kotlin

在某些情况下,您可能希望使用非 XA 处理某些 JMS 消息ConnectionFactory. 例如,您的 JMS 处理逻辑可能比 XA 超时花费的时间更长。spring-doc.cadn.net.cn

如果要使用非 XAConnectionFactory,您可以nonXaJmsConnectionFactory豆:spring-doc.cadn.net.cn

Java
public MyBean(@Qualifier("nonXaJmsConnectionFactory") ConnectionFactory connectionFactory) {
    // ...
}
Kotlin

为了保持一致性,jmsConnectionFactorybean 也是通过使用 bean 别名提供的xaJmsConnectionFactory:spring-doc.cadn.net.cn

Java
public MyBean(@Qualifier("xaJmsConnectionFactory") ConnectionFactory connectionFactory) {
    // ...
}
Kotlin

8.3. 支持嵌入式事务管理器

XAConnectionFactoryWrapperXADataSourceWrapper接口可用于支持嵌入式事务管理器。 接口负责包装XAConnectionFactoryXADataSourcebean 并将它们公开为常规ConnectionFactoryDataSourcebean,它们以透明方式注册分布式事务。 DataSource 和 JMS 自动配置使用 JTA 变体,前提是您有一个JtaTransactionManagerbean 和相应的 XA 包装器 bean 中注册的ApplicationContext.spring-doc.cadn.net.cn

9. 接下来要读什么

现在,您应该对 Spring Boot 的核心功能以及 Spring Boot 通过自动配置提供支持的各种技术有了很好的了解。spring-doc.cadn.net.cn

接下来的几节详细介绍了如何将应用程序部署到云平台。 您可以在下一节中阅读有关构建容器映像的信息,也可以跳至生产就绪功能部分。spring-doc.cadn.net.cn