大多数应用程序在某些时候需要处理输入和输出问题。 Spring Boot 提供实用程序和与一系列技术的集成,以在您需要 IO 功能时提供帮助。 本节涵盖标准 IO 功能(例如缓存和验证)以及更高级的主题(例如调度和分布式事务)。 我们还将介绍调用远程 REST 或 SOAP 服务以及发送电子邮件。
1. 缓存
Spring Framework 支持以透明的方式向应用程序添加缓存. 从本质上讲,将缓存应用于方法上,根据缓存数据减少方法的执行次数. 缓存逻辑是透明的,不会对调用者造成任何干扰. 通过 @EnableCaching
注解启用缓存支持,Spring Boot 就会自动配置缓存设置.
有关更多详细信息,请查看 Spring Framework 参考文档的 相关部分 . |
简而言之,为服务添加缓存的操作就像在其方法中添加注解一样简单,如下所示:
@Component
public class MyMathService {
@Cacheable("piDecimals")
public int computePiDecimal(int precision) {
...
}
}
此示例展示了如何在代价可能高昂的操作上使用缓存. 在调用 computePiDecimal
之前,缓存支持会在 piDecimals
缓存中查找与 i
参数匹配的项. 如果找到,则缓存中的内容会立即返回给调用者,并不会调用该方法. 否则,将调用该方法,并在返回值之前更新缓存.
您还可以使用标准 JSR-107 (JCache) 注解 (例如 @CacheResult ) . 但是,我们强烈建议您不要将 Spring Cache 和 JCache 注解混合使用.
|
如果您不添加任何指定的缓存库,Spring Boot 会自动配置一个使用 concurrent map 的 simple provider . 当需要缓存时 (例如前面示例中的 piDecimals
) ,该 simple provider 会为您创建缓存. 不推荐将 simple provider 用于生产环境,但它非常适合入门并帮助您了解这些功能.
当您决定使用缓存提供者时,请务必阅读其文档以了解如何配置应用程序. 几乎所有提供者都要求您显式配置应用程序中使用的每个缓存. 有些提供了自定义 spring.cache.cache-names
属性以定义默认缓存.
1.1. 支持的缓存提供者
缓存抽象不提供存储实现,其依赖于 org.springframework.cache.Cache
和 org.springframework.cache.CacheManager
接口的抽象实现.
如果您未定义 CacheManager
类型的 bean 或名为 cacheResolver
的 CacheResolver
(请参阅 CachingConfigurer
) ,则 Spring Boot 会尝试检测以下提供者 (按序号顺序) :
-
JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
此外,https://github.com/spring-projects/spring-boot-data-geode[Spring Boot for Apache Geode] 提供了 使用 Apache Geode 作为自动配置缓存提供者。
也可以通过设置 spring.cache.type 属性来强制指定缓存提供者. 如果您需要在某些环境 (比如测试) 中 完全禁用缓存,请使用此属性.
|
使用 spring-boot-starter-cache “Starter” 快速添加基本的缓存依赖. starter 引入了 spring-context-support . 如果手动添加依赖,则必须包含 spring-context-support 才能使用 JCache、EhCache 2.x 或 Caffeine 支持.
|
如果通过 Spring Boot 自动配置 CacheManager
,则可以通过暴露一个实现了 CacheManagerCustomizer
接口的 bean,在完全初始化之前进一步调整其配置. 以下示例设置了一个 flag,表示应将 null
值传递给底层 map:
@Configuration(proxyBeanMethods = false)
public class MyCacheManagerConfiguration {
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return (cacheManager) -> cacheManager.setAllowNullValues(false);
}
}
在前面示例中,需要一个自动配置的 ConcurrentMapCacheManager . 如果不是这种情况 (您提供了自己的配置或自动配置了不同的缓存提供者) ,则根本不会调用 customizer. 您可以拥有多个 customizer,也可以使用 @Order 或 Ordered 来排序它们.
|
1.1.1. Generic
如果上下文定义了至少一个 org.springframework.cache.Cache
bean,则使用 Generic 缓存. 将创建一个包装所有该类型 bean 的 CacheManager
.
1.1.2. JCache (JSR-107)
JCache 通过 classpath 上的 javax.cache.spi.CachingProvider
(即 classpath 上存在符合 JSR-107 的缓存库) 来引导,jCacheCacheManager
由 spring-boot-starter-cache
starter 提供. 您可以使用各种兼容库,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"
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.Configuration
bean,则会使用它来自定义. -
使用
CacheManager
的引用调用org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
bean 以进行完全自定义.
如果定义了一个标准的 javax.cache.CacheManager bean,它将自动包装进一个抽象所需的 org.springframework.cache.CacheManager 实现中,而不会应用自定义配置.
|
1.1.3. EhCache 2.x
如果可以在 classpath 的根目录中找到名为 ehcache.xml
的文件,则使用 EhCache 2.x. 如果找到 EhCache 2.x,则使用 spring-boot-starter-cache
starter 提供的 EhCacheCacheManager
来启动缓存管理器. 还可以提供其他配置文件,如下所示:
spring:
cache:
ehcache:
config: "classpath:config/another-config.xml"
1.1.4. Hazelcast
Spring Boot 对 Hazelcast 的支持一般. 如果自动配置了一个 HazelcastInstance
,它将自动包装进 CacheManager
中.
1.1.5. Infinispan
Infinispan 没有默认的配置文件位置,因此必须明确指定. 否则将使用默认配置加载.
spring:
cache:
infinispan:
config: "infinispan.xml"
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存. 如果定义了自定义 ConfigurationBuilder
bean,则它将用于自定义缓存.
Infinispan 在 Spring Boot 中的支持仅限于内嵌模式,非常简单. 如果你想要更多选项,你应该使用官方的 Infinispan Spring Boot starter. 有关更多详细信息,请参阅 Infinispan 文档 . |
1.1.6. Couchbase
如果 Spring Data Couchbase 可用并且已 配置 Couchbase,则会自动配置 CouchbaseCacheManager
. 通过设置 spring.cache.cache-names
属性可以在启动时创建其他缓存,并且可以使用 spring.cache.couchbase.*
属性配置缓存默认值. 以下配置创建 cache1
和 cache2
缓存,他们的有效时间为 10 分钟:
spring:
cache:
cache-names: "cache1,cache2"
couchbase:
expiration: "10m"
如果需要对配置进行更多控制,请考虑注册 CouchbaseCacheManagerBuilderCustomizer
bean.以下示例显示了一个定制器,该定制器为 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)));
}
}
1.1.7. Redis
如果 Redis 可用并已经配置,则应用程序会自动配置一个 RedisCacheManager
. 通过设置 spring.cache.cache-names
属性可以在启动时创建其他缓存,并且可以使用 spring.cache.redis.*
属性配置缓存默认值. 例如,以下配置创建 cache1
和 cache2
缓存,他们的有效时间为 10 分钟:
spring:
cache:
cache-names: "cache1,cache2"
redis:
time-to-live: "10m"
默认情况下,会添加一个 key 前缀,这样做是因为如果两个单独的缓存使用了相同的键,Redis 不支持重叠 key,而缓存也不能返回无效值. 如果您创建自己的 RedisCacheManager ,我们强烈建议您启用此设置.
|
您可以通过添加自己的 RedisCacheConfiguration @Bean 来完全控制配置. 如果您想自定义序列化策略,这种方式可能很有用.
|
如果您需要控制更多的配置,请考虑注册 RedisCacheManagerBuilderCustomizer
bean.
以下示例显示了一个自定义的配置,配置了 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)));
}
}
1.1.8. Caffeine
Caffeine 是一个使用了 Java 8 重写 Guava 缓存,用于取代 Guava 支持的缓存库. 如果 Caffeine 存在,则应用程序会自动配置一个 CaffeineCacheManager
(由 spring-boot-starter-cache
starter 提供) .
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存,并且可以通过以下方式之一 (按序号顺序) 自定义缓存:
-
一个由
spring.cache.caffeine.spec
定义的缓存规范 -
一个已定义的
com.github.benmanes.caffeine.cache.CaffeineSpec
bean -
一个已定义的
com.github.benmanes.caffeine.cache.Caffeine
bean
例如,以下配置创建 cache1
和 cache2
缓存,最大大小为 500,有效时间 为 10 分钟:
spring:
cache:
cache-names: "cache1,cache2"
caffeine:
spec: "maximumSize=500,expireAfterAccess=600s"
如果定义了 com.github.benmanes.caffeine.cache.CacheLoader
bean,它将自动与 CaffeineCacheManager
关联. 由于 CacheLoader
将与缓存管理器管理的所有缓存相关联,因此必须将其定义为 CacheLoader<Object, Object>
. 自动配置会忽略所有其他泛型类型.
1.1.9. Simple
如果找不到其他提供者,则配置使用一个 ConcurrentHashMap
作为缓存存储的简单实现. 如果您的应用程序中没有缓存库,则该项为默认值. 默认情况下,会根据需要创建缓存,但您可以通过设置 cache-names
属性来限制可用缓存的列表. 例如,如果只需要 cache1
和 cache2
缓存,请按如下设置 cache-names
属性:
spring:
cache:
cache-names: "cache1,cache2"
如果这样做了,并且您的应用程序使用了未列出的缓存,则运行时在它需要缓存时会触发失败,但在启动时则不会. 这类似于真实缓存提供者在使用未声明的缓存时触发的行为方式.
2. Hazelcast
如果 Hazelcast 在 classpath 上并有合适的配置,则 Spring Boot 会自动配置一个可以在应用程序中注入的 HazelcastInstance
.
Spring Boot 首先尝试通过检查以下配置选项来创建一个客户端:
-
存在
com.hazelcast.client.config.ClientConfig
bean. -
spring.hazelcast.config
属性定义的配置文件. -
存在
hazelcast.client.config
系统属性. -
工作目录中或 classpath 根目录下的
hazelcast-client.xml
. -
工作目录中或 classpath 根目录下的
hazelcast-client.yaml
.
Spring Boot 支持 Hazelcast 4 和 Hazelcast 3. 如果降级到 Hazelcast 3, 应该将 hazelcast-client 添加到类路径中以配置客户端.
|
如果无法创建客户端,则 Spring Boot 尝试配置嵌入式服务器.
如果定义了 com.hazelcast.config.Config
bean,则 Spring Boot 会使用它. 如果您的配置定义了实例名称,Spring Boot 会尝试查找现有的实例,而不是创建新实例.
您还可以指定通过配置使用的 Hazelcast 配置文件,如以下示例所示:
spring:
hazelcast:
config: "classpath:config/my-hazelcast.xml"
否则,Spring Boot 会尝试从默认位置查找 Hazelcast 配置: 工作目录或 classpath 根目录中的 hazelcast.xml
,或相同位置中的 .yaml
文件. 我们还检查是否设置了 hazelcast.config
系统属性. 有关更多详细信息,请参见 Hazelcast documentation.
Spring Boot 还为 Hazelcast 提供了缓存支持. 如果启用了缓存,HazelcastInstance 将自动包装在 CacheManager 实现中.
|
3. Quartz Scheduler
Spring Boot 提供了几种使用 Quartz 调度器的便捷方式,它们来自 spring-boot-starter-quartz
“Starter”. 如果 Quartz 可用,则 Spring Boot 将自动配置 Scheduler
(通过 SchedulerFactoryBean
抽象) .
自动选取以下类型的 Bean 并将其与 Scheduler
关联起来:
-
JobDetail
: 定义一个特定的 job. 可以使用JobBuilder
API 构建JobDetail
实例. -
Calendar
. -
Trigger
: 定义何时触发 job.
默认使用内存存储方式的 JobStore
. 但如果应用程序中有 DataSource
bean,并且配置了 spring.quartz.job-store-type
属性,则可以配置基于 JDBC 的存储,如下所示:
spring:
quartz:
job-store-type: "jdbc"
使用 JDBC 存储时,可以在启动时初始化 schema (表结构) ,如下所示:
spring:
quartz:
jdbc:
initialize-schema: "always"
默认将使用 Quartz 库提供的标准脚本检测并初始化数据库. 这些脚本会删除现有表,在每次重启时删除所有触发器. 可以通过设置 spring.quartz.jdbc.schema 属性来提供自定义脚本.
|
要让 Quartz 使用除应用程序主 DataSource
之外的 DataSource
,请声明一个 DataSource
bean,使用 @QuartzDataSource
注解其 @Bean
方法. 这样做可确保 SchedulerFactoryBean
和 schema 初始化都使用 Quartz 指定的 DataSource
.类似地,要让 Quartz 使用应用程序的主 TransactionManager
之外的 TransactionManager
来声明 TransactionManager
bean,并用 @QuartzTransactionManager
注解其 @Bean
方法.
默认情况下,配置创建的 job 不会覆盖已从持久 job 存储读取的已注册的 job. 要启用覆盖现有的 job 定义,请设置 spring.quartz.overwrite-existing-jobs
属性.
Quartz 调取器配置可以使用 spring.quartz
属性和 SchedulerFactoryBeanCustomizer
bean 进行自定义,它们允许以编程方式的 SchedulerFactoryBean
自定义. 可以使用 spring.quartz.properties.*
自定义高级 Quartz 配置属性.
需要强调的是,Executor bean 与调度程序没有关联,因为 Quartz 提供了通过 spring.quartz.properties 配置调度器的方法. 如果需要自定义 Actuator ,请考虑实现 SchedulerFactoryBeanCustomizer .
|
job 可以定义 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);
}
}
4. 发送邮件
Spring Framework 提供了一个使用 JavaMailSender
接口发送电子邮件的简单抽象,Spring Boot 为其提供了自动配置以及一个 starter 模块.
有关如何使用 JavaMailSender 的详细说明,请参阅 参考文档. |
如果 spring.mail.host
和相关库 (由 spring-boot-starter-mail
定义) 可用,则创建默认的 JavaMailSender
(如果不存在) . 可以通过 spring.mail
命名空间中的配置项进一步自定义发件人. 有关更多详细信息,请参阅 MailProperties
.
特别是,某些默认超时时间的值是无限的,您可能想更改它以避免线程被无响应的邮件服务器阻塞,如下示例所示:
spring:
mail:
properties:
"[mail.smtp.connectiontimeout]": 5000
"[mail.smtp.timeout]": 3000
"[mail.smtp.writetimeout]": 5000
也可以使用 JNDI 中的现有 Session
配置一个 JavaMailSender
:
spring:
mail:
jndi-name: "mail/Session"
设置 jndi-name
时,它优先于所有其他与 Session 相关的设置.
5. Validation
只要 classpath 上存在 JSR-303 实现 (例如 Hibernate 验证器) ,就会自动启用 Bean Validation 1.1 支持的方法验证功能. 这允许 bean 方法在其参数和/或返回值上使用 javax.validation
约束进行注解. 带有此类注解方法的目标类需要在类级别上使用 @Validated
进行注解,以便搜索其内联约束注解的方法.
例如,以下服务触发第一个参数的验证,确保其大小在 8 到 10 之间:
@Service
@Validated
public class MyBean {
public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, Author author) {
return ...
}
}
解析 constraint messages 中的 {parameters}
时使用应用程序的 MessageSource
。
这允许您使用 您的应用程序的 messages.properties
文件 用于 Bean 验证消息。
解析参数后,使用 Bean Validation 的默认插值器完成消息插值。
6. 调用 REST Services
如果您的应用程序需要调用远程 REST 服务,这可以使用 Spring Framework 的 RestTemplate 或 WebClient
类.
6.1. RestTemplate
如果您的应用程序需要调用远程 REST 服务,这可以使用 Spring Framework 的 RestTemplate 类. 由于 RestTemplate
实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何自动配置的 RestTemplate
bean. 但是,
它会自动配置 RestTemplateBuilder
,可在需要时创建 RestTemplate
实例. 自动配置的 RestTemplateBuilder
确保将合适的 HttpMessageConverters
应用于 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);
}
}
RestTemplateBuilder 包含许多可用于快速配置 RestTemplate 的方法. 例如,要添加 BASIC auth 支持,可以使用 builder.basicAuthentication("user", "password").build() .
|
6.1.1. 自定义 RestTemplate
RestTemplate
自定义有三种主要方法,具体取决于您希望自定义的程度.
要想自定义的作用域尽可能地窄,请注入自动配置的 RestTemplateBuilder
,然后根据需要调用其方法. 每个方法调用都返回一个新的 RestTemplateBuilder
实例,因此自定义只会影响当前构建器.
要在应用程序作用域内添加自定义配置,请使用 RestTemplateCustomizer
bean. 所有这些 bean 都会自动注册到自动配置的 RestTemplateBuilder
,并应用于使用它构建的所有模板.
以下示例展示了一个 customizer,它为除 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
public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, request, context);
}
}
}
最后,您还可以创建自己的 RestTemplateBuilder
bean。为了防止关闭 RestTemplateBuilder
的自动配置,并防止任何 RestTemplateCustomizer
bean 被使用,请确保使用 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));
}
}
最极端 (也很少使用) 的选择是创建自己的 RestTemplateBuilder
bean. 这样做会关闭 RestTemplateBuilder
的自动配置,并阻止使用任何 RestTemplateCustomizer
bean.
6.2. WebClient
如果在 classpath 上存在 Spring WebFlux,则还可以选择使用 WebClient
来调用远程 REST 服务. 与 RestTemplate
相比,该客户端更具函数式风格并且完全响应式. 您可以在 Spring Framework 文档的相关部分中了解有关 WebClient
的更多信息.
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);
}
}
6.2.1. WebClient 运行时
Spring Boot 将自动检测用于驱动 WebClient
的 ClientHttpConnector
,具体取决于应用程序 classpath 上可用的类库. 目前支持 Reactor Netty ,Apache HttpClient 和 Jetty RS 客户端.
默认情况下 spring-boot-starter-webflux
starter 依赖于 io.projectreactor.netty:reactor-netty
,它包含了服务器和客户端的实现. 如果您选择将 Jetty 用作响应式服务器,则应添加 Jetty Reactive HTTP 客户端库依赖 org.eclipse.jetty:jetty-reactive-httpclient
. 服务器和客户端使用相同的技术具有一定优势,因为它会自动在客户端和服务器之间共享 HTTP 资源.
开发人员可以通过提供自定义的 ReactorResourceFactory
或 JettyResourceFactory
bean 来覆盖 Jetty 和 Reactor Netty 的资源配置 —— 这将同时应用于客户端和服务器.
如果您只希望覆盖客户端选项,则可以定义自己的 ClientHttpConnector
bean 并完全控制客户端配置.
您可以在 Spring Framework 参考文档中了解有关 WebClient
配置选项的更多信息.
6.2.2. 自定义 WebClient
WebClient
自定义有三种主要方法,具体取决于您希望自定义的程度.
要想自定义的作用域尽可能地窄,请注入自动配置的 WebClient.Builder
,然后根据需要调用其方法. WebClient.Builder
实例是有状态的: 构建器上的任何更改都会影响到之后所有使用它创建的客户端. 如果要使用相同的构建器创建多个客户端,可以考虑使用 WebClient.Builder other = builder.clone()
; 的方式克隆构建器.
要在应用程序作用域内对所有 WebClient.Builder
实例添加自定义,可以声明 WebClientCustomizer
bean 并在注入点局部更改 WebClient.Builder
.
最后,您可以回退到原始 API 并使用 WebClient.create(). 在这种情况下,不会应用自动配置或 WebClientCustomizer
.
7. Web Services
Spring Boot 提供 Web Service 自动配置,因此您要做的就是定义 Endpoints.
可以使用 spring-boot-starter-webservices
模块轻松访问 Spring Web Services 功能.
可以分别为 WSDL 和 XSD 自动创建 SimpleWsdl11Definition
和 SimpleXsdSchema
bean. 为此,请配置其位置,如下所示:
spring:
webservices:
wsdl-locations: "classpath:/wsdl"
7.1. 使用 WebServiceTemplate 调用 Web Service
如果您需要从应用程序调用远程 Web 服务,则可以使用 WebServiceTemplate
类. 由于 WebServiceTemplate
实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何自动配置的 WebServiceTemplate
bean.
但是,它会自动配置 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"));
}
}
默认情况下,WebServiceTemplateBuilder
使用 classpath 上的可用 HTTP 客户端库检测合适的基于 HTTP 的 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();
}
}
8. JTA 分布式事务
Spring Boot 通过使用 Atomikos 嵌入式事务管理器来支持跨多个 XA 资源的分布式 JTA 事务, 并弃用了 Bitronix 嵌入式事务管理器的支持,并在未来版本中删除. 部署在某些 Java EE 应用服务器 (Application Server) 上也支持 JTA 事务.
当检测到 JTA 环境时,Spring 的 JtaTransactionManager
将用于管理事务. 自动配置的 JMS、DataSource 和 JPA bean 已升级为支持 XA 事务. 您可以使用标准的 Spring 方式 (例如 @Transactional
) 来使用分布式事务. 如果您处于 JTA 环境中并且仍想使用本地事务,则可以将 spring.jta.enabled
属性设置为 false
以禁用 JTA 自动配置.
8.1. 使用 Atomikos 事务管理器
Atomikos 是一个流行的开源事务管理器,可以嵌入到 Spring Boot 应用程序中. 您可以使用 spring-boot-starter-jta-atomikos
starter 来获取相应的 Atomikos 库. Spring Boot 自动配置 Atomikos 并确保将合适的 depends-on
设置应用于 Spring bean,以确保启动和关闭顺序正确.
默认情况下,Atomikos 事务日志将写入应用程序主目录 (应用程序 jar 文件所在的目录) 中的 transaction-logs
目录. 您可以通过在 application.properties
文件中设置 spring.jta.log-dir
属性来自定义此目录的位置. 也可用 spring.jta.atomikos.properties
开头的属性来自定义 Atomikos UserTransactionServiceImp
. 有关完整的详细信息,请参阅 AtomikosProperties
Javadoc.
为确保多个事务管理器可以安全地协调相同的资源管理器,必须为每个 Atomikos 实例配置唯一 ID. 默认情况下,此 ID 是运行 Atomikos 的计算机的 IP 地址. 在生产环境中要确保唯一性,应为应用程序的每个实例配置 spring.jta.transaction-manager-id 属性,并使用不同的值.
|
8.2. 使用 Java EE 管理的事务管理器
如果将 Spring Boot 应用程序打包为 war
或 ear
文件并将其部署到 Java EE 应用程序服务器,则可以使用应用程序服务器的内置事务管理器. Spring Boot 尝试通过查找常见的 JNDI 位置 (java:comp/UserTransaction
、java:comp/TransactionManager
等) 来自动配置事务管理器. 如果使用应用程序服务器提供的事务服务,
通常还需要确保所有资源都由服务器管理并通过 JNDI 暴露. Spring Boot 尝试通过在 JNDI 路径 (java:/JmsXA
或 java:/JmsXA
) 中查找 ConnectionFactory
来自动配置 JMS,并且可以使用 spring.datasource.jndi-name
属性 属性来配置 DataSource
.
8.3. 混合使用 XA 与非 XA JMS 连接
使用 JTA 时,primary (主) JMS ConnectionFactory
bean 可识别 XA 并参与分布式事务.您可以注入到您的 bean 中,而无需使用任何 @Qualifier
:
public MyBean(ConnectionFactory connectionFactory) {
// ...
}
在某些情况下,您可能希望使用非 XA ConnectionFactory
处理某些 JMS 消息. 例如,您的 JMS 处理逻辑可能需要比 XA 超时时间更长的时间.
如果要使用非 XA ConnectionFactory
,可以使用 nonXaJmsConnectionFactory
bean:
public MyBean(@Qualifier("nonXaJmsConnectionFactory") ConnectionFactory connectionFactory) {
// ...
}
为了保持一致性,提供的 jmsConnectionFactory
bean 还需要使用 xaJmsConnectionFactory
别名.
public MyBean(@Qualifier("xaJmsConnectionFactory") ConnectionFactory connectionFactory) {
// ...
}
8.4. 支持嵌入式事务管理器
XAConnectionFactoryWrapper
和 XADataSourceWrapper
接口可用于支持其他嵌入式事务管理器. 接口负责包装 XAConnectionFactory
和 XADataSource
bean,并将它们暴露为普通的 ConnectionFactory
和 DataSource
bean,它们透明地加入分布式事务. DataSource
和 JMS 自动配置使用 JTA 变体,前提是您需要有一个 JtaTransactionManager
bean 和在 ApplicationContext
中注册有的相应 XA 包装器 (wrapper) bean.
AtomikosXAConnectionFactoryWrapper 和 AtomikosXADataSourceWrapper 为如何编写 XA 包装器提供了很好示例.
9. 下一步
您现在应该对 Spring Boot 的 core features 以及 Spring Boot 通过自动配置提供支持的各种技术有了很好的了解。