IO的
1. 缓存
Spring Framework 支持透明地向应用程序添加缓存。
从本质上讲,该抽象将缓存应用于方法,从而根据缓存中可用的信息减少执行次数。
缓存逻辑是透明应用的,不会对调用者产生任何干扰。
只要使用@EnableCaching注解。
| 查看 Spring Framework 参考的相关部分以获取更多详细信息。 |
简而言之,要将缓存添加到服务的作中,请将相关注释添加到其方法中,如以下示例所示:
@Component
public class MyMathService {
@Cacheable("piDecimals")
public int computePiDecimal(int precision) {
...
}
}
@Component
class MyMathService {
@Cacheable("piDecimals")
fun computePiDecimal(precision: Int): Int {
...
}
}
此示例演示了在可能代价高昂的作上使用缓存。
调用之前computePiDecimal,抽象会在piDecimals缓存,与i论点。
如果找到条目,则缓存中的内容将立即返回给调用方,并且不会调用该方法。
否则,将调用该方法,并在返回值之前更新缓存。
您还可以使用标准 JSR-107 (JCache) 注释(例如@CacheResult) 透明。
但是,我们强烈建议您不要混合和匹配 Spring Cache 和 JCache 注释。 |
如果您不添加任何特定的缓存库,Spring Boot 会自动配置一个在内存中使用并发映射的简单提供程序。
当需要缓存时(例如piDecimals在前面的示例中),此提供程序会为您创建它。
不建议将简单的提供程序用于生产使用,但它非常适合入门并确保您了解这些功能。
当您决定要使用的缓存提供程序时,请务必阅读其文档以了解如何配置应用程序使用的缓存。
几乎所有提供程序都要求显式配置在应用程序中使用的每个缓存。
有些提供了一种自定义默认缓存的方法,由spring.cache.cache-names财产。
1.1. 支持的缓存提供程序
缓存抽象不提供实际的存储,而是依赖于org.springframework.cache.Cache和org.springframework.cache.CacheManager接口。
如果您尚未定义类型为CacheManager或CacheResolver叫cacheResolver(参见CachingConfigurer),Spring Boot 尝试检测以下提供程序(按指示的顺序):
如果CacheManager由 Spring Boot 自动配置,可以通过设置spring.cache.type财产。
如果您需要在某些环境(例如测试)中使用无作缓存,请使用此属性。 |
使用spring-boot-starter-cache“Starter”用于快速添加基本缓存依赖项。
首发带入spring-context-support.
如果手动添加依赖项,则必须包含spring-context-support以便使用 JCache 或 Caffeine 支持。 |
如果CacheManager由 Spring Boot 自动配置,您可以通过公开实现CacheManagerCustomizer接口。
以下示例设置了一个标志来说明null不应将值向下传递给底层映射:
@Configuration(proxyBeanMethods = false)
public class MyCacheManagerConfiguration {
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return (cacheManager) -> cacheManager.setAllowNullValues(false);
}
}
@Configuration(proxyBeanMethods = false)
class MyCacheManagerConfiguration {
@Bean
fun cacheManagerCustomizer(): CacheManagerCustomizer<ConcurrentMapCacheManager> {
return CacheManagerCustomizer { cacheManager ->
cacheManager.isAllowNullValues = false
}
}
}
在前面的示例中,自动配置的ConcurrentMapCacheManager是意料之中的。
如果不是这种情况(您提供了自己的配置或自动配置了不同的缓存提供程序),则根本不会调用定制器。
您可以根据需要拥有任意数量的定制器,也可以使用@Order或Ordered. |
1.1.2. JCache (JSR-107)
JCache 是通过存在javax.cache.spi.CachingProvider在类路径上(即,类路径上存在一个符合 JSR-107 的缓存库),并且JCacheCacheManager由spring-boot-starter-cache“入门”。
有各种兼容库可用,Spring Boot 为 Ehcache 3、Hazelcast 和 Infinispan 提供依赖管理。
也可以添加任何其他兼容库。
可能会出现多个提供程序,在这种情况下,必须显式指定提供程序。 即使 JSR-107 标准没有强制执行标准化方法来定义配置文件的位置,Spring Boot 也会尽最大努力适应使用实现详细信息设置缓存,如以下示例所示:
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.example.MyCachingProvider
spring.cache.jcache.config=classpath:example.xml
# 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.cache.cache-names财产。 如果自定义javax.cache.configuration.Configurationbean 被定义,它用于自定义它们。 -
org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizerbean 使用CacheManager用于完全定制。
如果标准javax.cache.CacheManagerbean 时,它会自动包装在org.springframework.cache.CacheManager抽象所期望的实现。
不会对其应用进一步的自定义。 |
1.1.3. 榛子广播
Spring Boot 对 Hazelcast 有一般支持。
如果HazelcastInstance已自动配置,并且com.hazelcast:hazelcast-spring在类路径上,它会自动包装在CacheManager.
Hazelcast 可以用作符合 JCache 的缓存或 SpringCacheManager合规缓存。
设置spring.cache.type自hazelcast,Spring Boot 将使用CacheManager基于实施。
如果要将 Hazelcast 用作符合 JCache 的缓存,请将spring.cache.type自jcache.
如果您有多个符合 JCache 的缓存提供程序并希望强制使用 Hazelcast,则必须显式设置 JCache 提供程序。 |
1.1.4. 无限跨度
Infinispan 没有默认配置文件位置,因此必须显式指定。 否则,将使用默认引导程序。
spring.cache.infinispan.config=infinispan.xml
spring:
cache:
infinispan:
config: "infinispan.xml"
可以通过在启动时创建缓存,方法是将spring.cache.cache-names财产。
如果自定义ConfigurationBuilderbean 定义,它用于自定义缓存。
为了与 Spring Boot 的 Jakarta EE 9 基线兼容,Infinispan 的-jakarta必须使用模块。
对于每个具有-jakartavariant,则必须使用该变型来代替标准模块。
例如infinispan-core-jakarta和infinispan-commons-jakarta必须用来代替infinispan-core和infinispan-commons分别。
1.1.5. 库奇库
如果 Spring Data Couchbase 可用并且配置了 Couchbase,则CouchbaseCacheManager是自动配置的。
可以通过设置spring.cache.cache-names属性和缓存默认值可以通过使用spring.cache.couchbase.*性能。
例如,以下配置会创建cache1和cache2条目过期时间为 10 分钟的缓存:
spring.cache.cache-names=cache1,cache2
spring.cache.couchbase.expiration=10m
spring:
cache:
cache-names: "cache1,cache2"
couchbase:
expiration: "10m"
如果您需要对配置进行更多控制,请考虑注册CouchbaseCacheManagerBuilderCustomizer豆。
以下示例显示了一个定制器,该定制器为cache1和cache2:
@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)));
}
}
@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)
如果 Redis 可用并已配置,则RedisCacheManager是自动配置的。
可以通过设置spring.cache.cache-names属性和缓存默认值可以通过使用spring.cache.redis.*性能。
例如,以下配置会创建cache1和cache2生存时间为 10 分钟的缓存:
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=10m
spring:
cache:
cache-names: "cache1,cache2"
redis:
time-to-live: "10m"
默认情况下,会添加键前缀,以便如果两个单独的缓存使用相同的键,Redis 不会有重叠的键,并且不能返回无效值。
如果您创建自己的设置,强烈建议您保持启用此设置RedisCacheManager. |
您可以通过添加RedisCacheConfiguration @Bean你自己的。
如果需要自定义默认序列化策略,这可能很有用。 |
如果您需要对配置进行更多控制,请考虑注册RedisCacheManagerBuilderCustomizer豆。 以下示例显示了一个定制器,该定制器配置了特定的生存时间cache1和cache2:
@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)));
}
}
@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 的支持。如果存在 Caffeine,则CaffeineCacheManager(由spring-boot-starter-cache“Starter”)是自动配置的。可以通过设置spring.cache.cache-names属性,可以通过以下选项之一进行自定义(按指示的顺序):
-
由
spring.cache.caffeine.spec -
一个
com.github.benmanes.caffeine.cache.CaffeineSpecbean 被定义 -
一个
com.github.benmanes.caffeine.cache.Caffeinebean 被定义
例如,以下配置会创建cache1和cache2最大大小为 500 且生存时间为 10 分钟的缓存
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
spring:
cache:
cache-names: "cache1,cache2"
caffeine:
spec: "maximumSize=500,expireAfterAccess=600s"
如果com.github.benmanes.caffeine.cache.CacheLoaderbean 时,它会自动与CaffeineCacheManager. 由于CacheLoader将与缓存管理器管理的所有缓存相关联,则必须将其定义为CacheLoader<Object, Object>. 自动配置将忽略任何其他泛型类型。
1.1.8. 缓存2k
Cache2k 是一个内存缓存。如果存在 Cache2k spring 集成,则SpringCache2kCacheManager是自动配置的。
可以通过在启动时创建缓存,方法是将spring.cache.cache-names财产。 缓存默认值可以使用Cache2kBuilderCustomizer豆。 以下示例显示了一个定制器,该定制器将缓存的容量配置为 200 个条目,过期时间为 5 分钟:
@Configuration(proxyBeanMethods = false)
public class MyCache2kDefaultsConfiguration {
@Bean
public Cache2kBuilderCustomizer myCache2kDefaultsCustomizer() {
return (builder) -> builder.entryCapacity(200)
.expireAfterWrite(5, TimeUnit.MINUTES);
}
}
@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财产。 例如,如果您只想要cache1和cache2caches,将cache-names属性如下:
spring.cache.cache-names=cache1,cache2
spring:
cache:
cache-names: "cache1,cache2"
如果这样做,并且应用程序使用未列出的缓存,则在运行时需要缓存时会失败,但在启动时不会失败。这类似于使用未声明缓存时“真实”缓存提供程序的行为方式。
2. 榛色
如果 Hazelcast 位于类路径上并且找到合适的配置,Spring Boot 会自动配置一个HazelcastInstance您可以将其注入到应用程序中。
Spring Boot首先通过检查以下配置选项来尝试创建客户端:
-
存在
com.hazelcast.client.config.ClientConfig豆。 -
由
spring.hazelcast.config财产。 -
的存在
hazelcast.client.config系统属性。 -
一个
hazelcast-client.xml在工作目录中或类路径的根目录中。 -
一个
hazelcast-client.yaml(或hazelcast-client.yml) 在工作目录或类路径的根目录中。
如果无法创建客户端,Spring Boot 会尝试配置嵌入式服务器。如果定义com.hazelcast.config.Configbean,Spring Boot 使用它。如果您的配置定义了实例名称,则 Spring Boot 会尝试查找现有实例而不是创建新实例。
您还可以指定要通过配置使用的 Hazelcast 配置文件,如以下示例所示:
spring.hazelcast.config=classpath:config/my-hazelcast.xml
spring:
hazelcast:
config: "classpath:config/my-hazelcast.xml"
否则,Spring Boot 会尝试从默认位置查找 Hazelcast 配置:hazelcast.xml在工作目录中或类路径的根目录中,或相同位置的 YAML 对应项。
我们还会检查hazelcast.config系统属性。
有关更多详细信息,请参阅 Hazelcast 文档。
默认情况下,@SpringAware在 Hazelcast 组件上支持。
这ManagementContext可以通过声明HazelcastConfigCustomizer带有@Order高于零。 |
Spring Boot 还对 Hazelcast 有显式缓存支持。
如果启用了缓存,则HazelcastInstance会自动包装在CacheManager实现。 |
3. Quartz调度程序
Spring Boot 为使用 Quartz 调度器提供了多种便利,包括spring-boot-starter-quartz“入门”。
如果 Quartz 可用,则Scheduler自动配置(通过SchedulerFactoryBean抽象)。
以下类型的 bean 会自动选取并与Scheduler:
-
JobDetail:定义特定的作业。JobDetail实例可以使用JobBuilder应用程序接口。 -
Calendar. -
Trigger:定义何时触发特定作业。
默认情况下,内存中的JobStore被使用。
但是,如果DataSourcebean 在您的应用程序中可用,并且如果spring.quartz.job-store-type属性进行相应配置,如以下示例所示:
spring.quartz.job-store-type=jdbc
spring:
quartz:
job-store-type: "jdbc"
使用 JDBC 存储时,可以在启动时初始化模式,如以下示例所示:
spring.quartz.jdbc.initialize-schema=always
spring:
quartz:
jdbc:
initialize-schema: "always"
默认情况下,使用 Quartz 库提供的标准脚本来检测和初始化数据库。
这些脚本会删除现有表,并在每次重新启动时删除所有触发器。
也可以通过设置spring.quartz.jdbc.schema财产。 |
要让 Quartz 使用DataSource除了应用程序的主要内容DataSource,声明一个DataSourcebean,注释其@Bean方法@QuartzDataSource.
这样做可以确保特定于 Quartz 的DataSource由SchedulerFactoryBean以及用于模式初始化。
同样,要让 Quartz 使用TransactionManager除了应用程序的主要内容TransactionManager声明一个TransactionManagerbean,注释其@Bean方法@QuartzTransactionManager.
缺省情况下,配置创建的作业不会覆盖已从持久性作业存储中读取的已注册作业。
要启用覆盖现有作业定义,请将spring.quartz.overwrite-existing-jobs财产。
Quartz 调度器配置可以使用以下命令进行自定义spring.quartzproperties 和SchedulerFactoryBeanCustomizerbean,允许编程SchedulerFactoryBean定制。
高级 Quartz 配置属性可以使用以下命令进行自定义spring.quartz.properties.*.
特别是,一个Executorbean 与调度器无关,因为 Quartz 提供了一种通过spring.quartz.properties.
如果您需要自定义任务执行器,请考虑实现SchedulerFactoryBeanCustomizer. |
作业可以定义 setter 来注入数据映射属性。 常规 bean 也可以以类似的方式注入,如以下示例所示:
public class MySampleJob extends QuartzJobBean {
// 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);
}
}
class MySampleJob : QuartzJobBean() {
// 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 为其提供自动配置以及入门模块。
有关如何使用的详细说明,请参阅参考文档JavaMailSender. |
如果spring.mail.host和相关库(定义为spring-boot-starter-mail) 可用,默认值JavaMailSender如果不存在,则创建。
可以通过配置项进一步自定义发送方spring.mailNamespace。
看MailProperties了解更多详情。
特别是,某些默认超时值是无限的,您可能希望更改它以避免线程被无响应的邮件服务器阻止,如以下示例所示:
spring.mail.properties[mail.smtp.connectiontimeout]=5000
spring.mail.properties[mail.smtp.timeout]=3000
spring.mail.properties[mail.smtp.writetimeout]=5000
spring:
mail:
properties:
"[mail.smtp.connectiontimeout]": 5000
"[mail.smtp.timeout]": 3000
"[mail.smtp.writetimeout]": 5000
也可以配置一个JavaMailSender与现有的Session来自 JNDI:
spring.mail.jndi-name=mail/Session
spring:
mail:
jndi-name: "mail/Session"
当jndi-name,则优先于所有其他与会话相关的设置。
5. 验证
只要 JSR-303 实现(例如 Hibernate 验证器)在类路径上,Bean Validation 1.1 支持的方法验证功能就会自动启用。
这允许使用jakarta.validation对其参数和/或返回值的约束。
具有此类注释方法的目标类需要使用@Validated类型级别的注释,以便搜索其方法以查找内联约束注释。
例如,以下服务触发第一个参数的验证,确保其大小在 8 到 10 之间:
@Service
@Validated
public class MyBean {
public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, Author author) {
return ...
}
}
@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 的默认插值器完成消息插值。
要自定义Configuration用于构建ValidatorFactory,定义一个ValidationConfigurationCustomizer豆。
当定义了多个定制器 Bean 时,它们会根据其@Order注释或Ordered实现。
6. 调用 REST 服务
Spring Boot 提供了多种方便的方式来调用远程 REST 服务。
如果您正在开发一个非阻塞响应式应用程序并且您正在使用 Spring WebFlux,那么您可以使用WebClient.
如果您更喜欢阻止 API,那么您可以使用RestClient或RestTemplate.
6.1. 网络客户端
如果您的类路径上有 Spring WebFlux,我们建议您使用WebClient调用远程 REST 服务。
这WebClient接口提供了函数式 API,并且是完全响应式的。
您可以了解有关WebClient在 Spring Framework 文档的专用部分中。
如果您没有编写响应式 Spring WebFlux 应用程序,则可以使用RestClient而不是WebClient.
这提供了类似的功能 API,但是阻塞而不是响应式的。 |
Spring Boot 创建并预配置原型WebClient.Builder豆子给你。
强烈建议将其注入组件中并使用它来创建WebClient实例。
Spring Boot 正在配置该构建器以共享 HTTP 资源并以与服务器相同的方式反映编解码器设置(请参阅 WebFlux HTTP 编解码器自动配置)等。
以下代码显示了一个典型的示例:
@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);
}
}
@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.1.1. WebClient 运行时
Spring Boot 将自动检测哪个ClientHttpConnector用于驾驶WebClient取决于应用程序类路径上可用的库。
按优先级顺序,支持以下客户端:
-
反应器网
-
Jetty RS 客户端
-
Apache Http客户端
-
JDK Http客户端
如果类路径上有多个客户端可用,则将使用首选客户端。
这spring-boot-starter-webfluxStarters取决于io.projectreactor.netty:reactor-netty默认情况下,它带来了服务器和客户端实现。如果您选择使用 Jetty 作为响应式服务器,则应添加对 Jetty 响应式 HTTP 客户端库的依赖项,org.eclipse.jetty:jetty-reactive-httpclient. 对服务器和客户端使用相同的技术有其优势,因为它会自动在客户端和服务器之间共享 HTTP 资源。
开发人员可以通过提供自定义ReactorResourceFactory或JettyResourceFactorybean - 这将应用于客户端和服务器。
如果您希望为客户端覆盖该选择,您可以定义自己的选择ClientHttpConnectorbean 并完全控制客户端配置。
6.1.2. Web客户端定制
主要有三种方法WebClient自定义,具体取决于您希望应用自定义的范围。
若要使任何自定义的范围尽可能窄,请注入自动配置的WebClient.Builder然后根据需要调用其方法。WebClient.Builder实例是有状态的:构建器上的任何更改都会反映在随后使用它创建的所有客户端中。
如果您想使用相同的构建器创建多个客户端,您还可以考虑使用WebClient.Builder other = builder.clone();.
为所有应用范围的增材定制WebClient.Builder实例,您可以声明WebClientCustomizerbean 并将WebClient.Builder在注射点局部。
最后,您可以回退到原始 API 并使用WebClient.create().
在这种情况下,没有自动配置或WebClientCustomizer被应用。
6.1.3. Web客户端SSL支持
如果您需要在ClientHttpConnector由WebClient,您可以注入一个WebClientSsl实例,可与构建器的apply方法。
这WebClientSsl接口提供对您在application.properties或application.yaml文件。
以下代码显示了一个典型的示例:
@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);
}
}
@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)
}
}
6.2. Rest客户端
如果您没有在应用程序中使用 Spring WebFlux 或 Project Reactor,我们建议您使用RestClient调用远程 REST 服务。
这RestClient接口提供了一个函数式的阻塞 API。
Spring Boot 创建并预配置原型RestClient.Builder豆子给你。
强烈建议将其注入组件中并使用它来创建RestClient实例。 Spring Boot 正在使用HttpMessageConverters和适当的ClientHttpRequestFactory.
以下代码显示了一个典型的示例:
@Service
public class MyService {
private final RestClient restClient;
public MyService(RestClient.Builder restClientBuilder) {
this.restClient = restClientBuilder.baseUrl("https://example.org").build();
}
public Details someRestCall(String name) {
return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
}
}
@Service
class MyService(restClientBuilder: RestClient.Builder) {
private val restClient: RestClient
init {
restClient = restClientBuilder.baseUrl("https://example.org").build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name)
.retrieve().body(Details::class.java)!!
}
}
6.2.1. RestClient 自定义
主要有三种方法RestClient自定义,具体取决于您希望应用自定义的范围。
若要使任何自定义的范围尽可能窄,请注入自动配置的RestClient.Builder然后根据需要调用其方法。RestClient.Builder实例是有状态的:构建器上的任何更改都会反映在随后使用它创建的所有客户端中。
如果您想使用相同的构建器创建多个客户端,您还可以考虑使用RestClient.Builder other = builder.clone();.
为所有应用范围的增材定制RestClient.Builder实例,您可以声明RestClientCustomizerbean 并将RestClient.Builder在注射点局部。
最后,您可以回退到原始 API 并使用RestClient.create().
在这种情况下,没有自动配置或RestClientCustomizer被应用。
6.2.2. RestClient SSL 支持
如果您需要在ClientHttpRequestFactory由RestClient,您可以注入一个RestClientSsl实例,可与构建器的apply方法。
这RestClientSsl接口提供对您在application.properties或application.yaml文件。
以下代码显示了一个典型的示例:
@Service
public class MyService {
private final RestClient restClient;
public MyService(RestClient.Builder restClientBuilder, RestClientSsl ssl) {
this.restClient = restClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
}
public Details someRestCall(String name) {
return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
}
}
@Service
class MyService(restClientBuilder: RestClient.Builder, ssl: RestClientSsl) {
private val restClient: RestClient
init {
restClient = restClientBuilder.baseUrl("https://example.org")
.apply(ssl.fromBundle("mybundle")).build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name)
.retrieve().body(Details::class.java)!!
}
}
如果您需要应用 SSL 捆绑包之外的其他自定义,则可以使用ClientHttpRequestFactorySettings类与ClientHttpRequestFactories:
@Service
public class MyService {
private final RestClient restClient;
public MyService(RestClient.Builder restClientBuilder, SslBundles sslBundles) {
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
.withReadTimeout(Duration.ofMinutes(2))
.withSslBundle(sslBundles.getBundle("mybundle"));
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(settings);
this.restClient = restClientBuilder.baseUrl("https://example.org").requestFactory(requestFactory).build();
}
public Details someRestCall(String name) {
return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
}
}
@Service
class MyService(restClientBuilder: RestClient.Builder, sslBundles: SslBundles) {
private val restClient: RestClient
init {
val settings = ClientHttpRequestFactorySettings.DEFAULTS
.withReadTimeout(Duration.ofMinutes(2))
.withSslBundle(sslBundles.getBundle("mybundle"))
val requestFactory = ClientHttpRequestFactories.get(settings)
restClient = restClientBuilder
.baseUrl("https://example.org")
.requestFactory(requestFactory).build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name).retrieve().body(Details::class.java)!!
}
}
6.3. Rest模板
Spring 框架的RestTemplate班级前期RestClient并且是许多应用程序用来调用远程 REST 服务的经典方式。
您可以选择使用RestTemplate当您有不想迁移到的现有代码时RestClient,或者因为你已经熟悉RestTemplate应用程序接口。
因为RestTemplate实例在使用前通常需要自定义,Spring Boot 不提供任何单个自动配置RestTemplate豆。
但是,它会自动配置一个RestTemplateBuilder,可用于创建RestTemplate实例。
自动配置的RestTemplateBuilder确保明智HttpMessageConverters和适当的ClientHttpRequestFactory应用于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);
}
}
@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().
6.3.1. RestTemplate 自定义
主要有三种方法RestTemplate自定义,具体取决于您希望应用自定义的范围。
若要使任何自定义的范围尽可能窄,请注入自动配置的RestTemplateBuilder然后根据需要调用其方法。
每个方法调用都会返回一个新的RestTemplateBuilder实例,因此自定义仅影响构建器的这种使用。
要进行应用程序范围的增材定制,请使用RestTemplateCustomizer豆。
所有这些此类 bean 都会自动注册到自动配置的RestTemplateBuilder并应用于使用它构建的任何模板。
以下示例显示了一个定制器,该定制器配置了对除192.168.0.5:
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);
}
}
}
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 的自动配置所做的事情相匹配,只是还指定了自定义连接和读取超时:
@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));
}
}
@Configuration(proxyBeanMethods = false)
class MyRestTemplateBuilderConfiguration {
@Bean
fun restTemplateBuilder(configurer: RestTemplateBuilderConfigurer): RestTemplateBuilder {
return configurer.configure(RestTemplateBuilder()).setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(2))
}
}
最极端(且很少使用)的选项是创建自己的RestTemplateBuilderbean 而不使用配置器。
除了替换自动配置的构建器外,这还可以防止任何RestTemplateCustomizer豆子不再被使用。
6.3.2. RestTemplate SSL 支持
如果您需要在RestTemplate,您可以将 SSL 捆绑包应用于RestTemplateBuilder如以下示例所示:
@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);
}
}
@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)!!
}
}
7. 网络服务
Spring Boot 提供 Web 服务自动配置,因此您只需定义Endpoints.
Spring Web Services 功能可以通过spring-boot-starter-webservices模块。
SimpleWsdl11Definition和SimpleXsdSchema可以分别为您的 WSDL 和 XSD 自动创建 bean。
为此,请配置其位置,如以下示例所示:
spring.webservices.wsdl-locations=classpath:/wsdl
spring:
webservices:
wsdl-locations: "classpath:/wsdl"
7.1. 使用 WebServiceTemplate 调用 Web 服务
如果您需要从应用程序调用远程 Web 服务,则可以使用WebServiceTemplate类。
因为WebServiceTemplate实例在使用前通常需要自定义,Spring Boot 不提供任何单个自动配置WebServiceTemplate豆。
但是,它会自动配置一个WebServiceTemplateBuilder,可用于创建WebServiceTemplate实例。
以下代码显示了一个典型的示例:
@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"));
}
}
@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在类路径上使用可用的 HTTP 客户端库。您还可以自定义读取和连接超时,如下所示:
@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();
}
}
@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 事务。
当检测到 JTA 环境时,Spring 的JtaTransactionManager用于管理事务。自动配置的 JMS、DataSource 和 JPA bean 已升级为支持 XA 事务。您可以使用标准的 Spring 习惯用法,例如@Transactional,以参与分布式事务。如果您在 JTA 环境中并且仍想使用本地事务,则可以将spring.jta.enabled属性设置为false以禁用 JTA 自动配置。
8.1. 使用 Jakarta EE 托管事务管理器
如果您将 Spring Boot 应用程序打包为war或ear文件并将其部署到 Jakarta EE 应用程序服务器,您可以使用应用程序服务器的内置事务管理器。Spring Boot 尝试通过查看常见的 JNDI 位置(java:comp/UserTransaction,java:comp/TransactionManager,依此类推)。当使用应用程序服务器提供的事务服务时,您通常还希望确保所有资源都由服务器管理并通过 JNDI 公开。Spring Boot 尝试通过查找ConnectionFactory在 JNDI 路径 (java:/JmsXA或java:/XAConnectionFactory),并且您可以使用spring.datasource.jndi-name属性配置您的DataSource.
8.2. 混合 XA 和非 XA JMS 连接
使用 JTA 时,主要 JMSConnectionFactorybean 是 XA 感知的,并参与分布式事务。您可以注入到您的 bean 中,而无需使用任何@Qualifier:
public MyBean(ConnectionFactory connectionFactory) {
// ...
}
在某些情况下,您可能希望使用非 XA 来处理某些 JMS 消息ConnectionFactory. 例如,您的 JMS 处理逻辑可能需要比 XA 超时更长的时间。
如果要使用非 XAConnectionFactory,您可以nonXaJmsConnectionFactory豆:
public MyBean(@Qualifier("nonXaJmsConnectionFactory") ConnectionFactory connectionFactory) {
// ...
}
为了保持一致性,该jmsConnectionFactoryBean 也通过使用 Bean 别名提供xaJmsConnectionFactory:
public MyBean(@Qualifier("xaJmsConnectionFactory") ConnectionFactory connectionFactory) {
// ...
}
8.3. 支持嵌入式事务管理器
这XAConnectionFactoryWrapper和XADataSourceWrapper接口可用于支持嵌入式事务管理器。接口负责包装XAConnectionFactory和XADataSource豆子并将它们公开为常规ConnectionFactory和DataSourcebean,它透明地注册到分布式事务中。DataSource 和 JMS 自动配置使用 JTA 变体,前提是您有一个JtaTransactionManagerbean 和适当的 XA 包装器 bean 在您的ApplicationContext.