输入输出
1. 缓存
Spring Framework 支持以透明方式向应用程序添加缓存。
抽象的核心是将缓存应用于方法,从而根据缓存中可用的信息减少执行次数。
缓存逻辑以透明方式应用,不会对调用程序造成任何干扰。
Spring Boot 会自动配置缓存基础设施,只要使用@EnableCaching
注解。
有关更多详细信息,请查看 Spring Framework 参考的相关部分。 |
简而言之,要将缓存添加到服务的作中,请将相关 Comments 添加到其方法中,如以下示例所示:
@Component
public class MyMathService {
@Cacheable("piDecimals")
public int computePiDecimal(int precision) {
...
}
}
@Component
class MyMathService {
@Cacheable("piDecimals")
fun computePiDecimal(precision: Int): Int {
...
}
}
此示例演示了如何在可能成本高昂的作中使用缓存。
调用computePiDecimal
中,抽象在piDecimals
cache 匹配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 会尝试检测以下提供程序(按指示的顺序):
-
JCache (JSR-107)(EhCache 3、Hazelcast、Infinispan 等)
如果CacheManager 由 Spring Boot 自动配置,则可以通过将spring.cache.type 财产。
如果需要在某些环境(例如测试)中使用无作缓存,请使用此属性。 |
使用spring-boot-starter-cache “Starter” 快速添加基本的缓存依赖项。
首发球员带来spring-context-support .
如果手动添加依赖项,则必须包含spring-context-support 以使用 JCache、EhCache 2.x 或 Caffeine 支持。 |
如果CacheManager
由 Spring Boot 自动配置,则可以通过公开实现CacheManagerCustomizer
接口。
下面的示例设置一个标志来表示null
值不应向下传递到底层 Map:
@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
“Starters”。
可以使用各种兼容的库,并且 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.Configuration
bean 的定义,则用于自定义它们。 -
org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
bean 是使用CacheManager
进行完全自定义。
如果标准的javax.cache.CacheManager bean 时,它会自动包装在org.springframework.cache.CacheManager 抽象期望的实现。
不会对其应用进一步的自定义。 |
1.1.3. EhCache 2.x
EhCache如果名为ehcache.xml
可以在 Classpath 的根目录中找到。
如果找到 EhCache 2.x,则EhCacheCacheManager
由spring-boot-starter-cache
“Starter” 用于引导缓存管理器。
还可以提供备用配置文件,如以下示例所示:
spring.cache.ehcache.config=classpath:config/another-config.xml
spring:
cache:
ehcache:
config: "classpath:config/another-config.xml"
1.1.4. 黑泽尔广播
Spring Boot 具有对 Hazelcast 的一般支持。
如果HazelcastInstance
已自动配置并且com.hazelcast:hazelcast-spring
位于 Classpath 上,它会自动包装在CacheManager
.
Hazelcast 可以用作符合 JCache 的缓存或用作 SpringCacheManager compliant 缓存。
设置spring.cache.type 自hazelcast ,Spring Boot 将使用CacheManager 基于实施。
如果要将 Hazelcast 用作符合 JCache 的缓存,请将spring.cache.type 自jcache .
如果您有多个符合 JCache 的缓存提供程序并希望强制使用 Hazelcast,则必须显式设置 JCache 提供程序。 |
1.1.5. Infinispan
Infinispan 没有默认的配置文件位置,因此必须显式指定它。 否则,将使用默认引导程序。
spring.cache.infinispan.config=infinispan.xml
spring:
cache:
infinispan:
config: "infinispan.xml"
可以在启动时通过设置spring.cache.cache-names
财产。
如果自定义ConfigurationBuilder
bean,它用于自定义缓存。
Spring Boot 中对 Infinispan 的支持仅限于嵌入式模式,并且非常基本。 如果你想要更多选项,你应该使用官方的 Infinispan Spring Boot Starters。 有关更多详细信息,请参阅 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
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.7. 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.8. 咖啡因
Caffeine 是 Guava 缓存的 Java 8 重写,它取代了对 Guava 的支持。
如果存在咖啡因,则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
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.CacheLoader
bean 时,它会自动关联到CaffeineCacheManager
.
由于CacheLoader
将与缓存管理器管理的所有缓存相关联,则必须将其定义为CacheLoader<Object, Object>
.
auto-configuration 会忽略任何其他泛型类型。
1.1.9. 缓存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.10. 简单
如果找不到其他提供程序,则使用ConcurrentHashMap
作为缓存存储的配置。
如果您的应用程序中不存在缓存库,则这是默认值。
默认情况下,缓存是根据需要创建的,但您可以通过设置cache-names
财产。
例如,如果您只想cache1
和cache2
caches,将cache-names
属性,如下所示:
spring.cache.cache-names=cache1,cache2
spring:
cache:
cache-names: "cache1,cache2"
如果您这样做,并且您的应用程序使用未列出的缓存,则它会在运行时需要缓存时失败,但在启动时不会失败。 这类似于使用未声明的缓存时“真实”缓存提供程序的行为方式。
2. Hazelcast
如果 Hazelcast 位于 Classpath 上并且找到合适的配置,则 Spring Boot 会自动配置一个HazelcastInstance
,您可以将其注入到您的应用程序中。
Spring Boot 首先尝试通过检查以下配置选项来创建客户端:
-
存在
com.hazelcast.client.config.ClientConfig
豆。 -
由
spring.hazelcast.config
财产。 -
存在
hazelcast.client.config
system 属性。 -
一个
hazelcast-client.xml
在工作目录中或 Classpath 的根目录中。 -
一个
hazelcast-client.yaml
(或hazelcast-client.yml
) 在 worker directory 或 classpath 的根目录中。
Hazelcast 3 支持已弃用。
如果您仍然需要降级到 Hazelcast 3,hazelcast-client 应添加到 Classpath 中以配置 Client 端。 |
如果无法创建 Client 端,则 Spring Boot 将尝试配置嵌入式服务器。
如果您定义了com.hazelcast.config.Config
bean,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
在工作目录或 Classpath 的根目录中,或者相同位置的 YAML 对应项。
我们还会检查hazelcast.config
system 属性。
有关更多详细信息,请参阅 Hazelcast 文档。
默认情况下,@SpringAware 在 Hazelcast 组件上。
这ManagementContext 可以通过声明HazelcastConfigCustomizer 带有@Order 高于零。 |
Spring Boot 还具有对 Hazelcast 的显式缓存支持。
如果启用了缓存,则HazelcastInstance 会自动包装在CacheManager 实现。 |
3. Quartz 调度器
Spring Boot 为使用 Quartz 调度程序提供了多种便利,包括spring-boot-starter-quartz
“Starters”。
如果 Quartz 可用,则Scheduler
是自动配置的(通过SchedulerFactoryBean
abstraction)。
以下类型的 bean 将被自动选取并与Scheduler
:
-
JobDetail
:定义特定的 Job。JobDetail
实例可以使用JobBuilder
应用程序接口。 -
Calendar
. -
Trigger
:定义何时触发特定作业。
默认情况下,内存中的JobStore
被使用。
但是,如果DataSource
bean 在您的应用程序中可用,并且如果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
除了应用程序的 mainDataSource
,声明一个DataSource
bean,为其@Bean
method 替换为@QuartzDataSource
.
这样做可以确保特定于 Quartz 的DataSource
被SchedulerFactoryBean
以及 schema 初始化。
同样,要让 Quartz 使用TransactionManager
除了应用程序的 mainTransactionManager
声明一个TransactionManager
bean,为其@Bean
method 替换为@QuartzTransactionManager
.
默认情况下,通过配置创建的作业不会覆盖已从持久性作业存储中读取的已注册作业。
要启用覆盖现有作业定义,请将spring.quartz.overwrite-existing-jobs
财产。
可以使用 Quartz Scheduler 配置进行自定义spring.quartz
properties 和SchedulerFactoryBeanCustomizer
bean,它允许以编程方式SchedulerFactoryBean
定制。
高级 Quartz 配置属性可使用spring.quartz.properties.*
.
特别是,Executor bean 与调度器无关,因为 Quartz 提供了一种通过spring.quartz.properties .
如果需要自定义任务执行程序,请考虑实现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);
}
}
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 为其提供自动配置以及 starter 模块。
如果spring.mail.host
和相关库(由spring-boot-starter-mail
) 可用,则默认JavaMailSender
如果不存在,则创建。
发送者可以通过spring.mail
Namespace。
看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
设置,则它优先于所有其他与 Session 相关的设置。
5. 验证
只要 JSR-303 实现(例如 Hibernate 验证器)在 Classpath 上,Bean Validation 1.1 支持的方法验证功能就会自动启用。
这允许 bean 方法使用javax.validation
对其参数和/或返回值的约束。
具有此类 Comments 方法的目标类需要使用@Validated
annotation 的 Comments,以便搜索其方法的内联约束 Comments。
例如,以下服务触发第一个参数的验证,确保其大小介于 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 的默认插值器完成消息插值。
6. 调用 REST 服务
如果您的应用程序调用远程 REST 服务,Spring Boot 使用RestTemplate
或WebClient
.
6.1. RestTemplate
如果需要从应用程序调用远程 REST 服务,可以使用 Spring Framework 的RestTemplate
类。
因为RestTemplate
实例在使用之前通常需要进行自定义,Spring Boot 不提供任何单一的自动配置RestTemplate
豆。
但是,它会自动配置RestTemplateBuilder
,可用于创建RestTemplate
实例。
自动配置的RestTemplateBuilder
确保 SensibleHttpMessageConverters
应用于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.1.1. RestTemplate HTTP 客户端
Spring Boot 将自动检测要使用的 HTTP 客户端RestTemplate
取决于应用程序 Classpath 上可用的库。
按优先顺序,支持以下客户端:
-
Apache HttpClient
-
OkHttp
-
简单 JDK 客户端 (
HttpURLConnection
)
如果 Classpath 上有多个 Client 端可用,则将使用最首选的 Client 端。
6.1.2. RestTemplate 自定义
有三种主要方法RestTemplate
自定义,具体取决于您希望自定义应用的范围。
要使任何自定义的范围尽可能窄,请注入自动配置的RestTemplateBuilder
然后根据需要调用其方法。
每个方法调用都会返回一个新的RestTemplateBuilder
实例,因此自定义项仅影响 Builder 的这种使用。
要进行应用程序范围的增材自定义,请使用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
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);
}
}
}
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, request: HttpRequest, context: HttpContext): HttpHost? {
if (target.hostName == "192.168.0.5") {
return null
}
return super.determineProxy(target, request, context)
}
}
}
最后,您可以定义自己的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));
}
}
@Configuration(proxyBeanMethods = false)
class MyRestTemplateBuilderConfiguration {
@Bean
fun restTemplateBuilder(configurer: RestTemplateBuilderConfigurer): RestTemplateBuilder {
return configurer.configure(RestTemplateBuilder()).setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(2))
}
}
最极端(也很少使用)的选项是创建自己的RestTemplateBuilder
Bean 的 Bean 中。
除了替换自动配置的构建器外,这还可以防止任何RestTemplateCustomizer
豆子被使用。
6.2. Web客户端
如果你的 classpath 中有 Spring WebFlux,你也可以选择使用WebClient
调用远程 REST 服务。
与RestTemplate
,这个客户端感觉更实用,并且完全被动。
您可以详细了解WebClient
在 Spring Framework 文档的 dedicated 部分。
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<Relationship.Details> {
return webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(
Relationship.Details::class.java
)
}
}
6.2.1. WebClient 运行时
Spring Boot 将自动检测哪个ClientHttpConnector
用于驾驶WebClient
取决于应用程序 Classpath 上可用的库。
按优先顺序,支持以下客户端:
-
Reactor Netty
-
Jetty RS 客户端
-
Apache HttpClient
-
JDK HttpClient
如果 Classpath 上有多个 Client 端可用,则将使用最首选的 Client 端。
这spring-boot-starter-webflux
Starter 依赖于io.projectreactor.netty:reactor-netty
默认情况下,它同时带来 server 和 client 实现。
如果您选择使用 Jetty 作为响应式服务器,则应添加对 Jetty 响应式 HTTP 客户端库的依赖项。org.eclipse.jetty:jetty-reactive-httpclient
.
对服务器和客户端使用相同的技术有其优势,因为它会自动在客户端和服务器之间共享 HTTP 资源。
开发人员可以通过提供自定义ReactorResourceFactory
或JettyResourceFactory
bean - 这将应用于客户端和服务器。
如果您希望为客户端覆盖该选择,您可以定义自己的ClientHttpConnector
bean 并完全控制客户端配置。
6.2.2. WebClient 自定义
有三种主要方法WebClient
自定义,具体取决于您希望自定义应用的范围。
要使任何自定义的范围尽可能窄,请注入自动配置的WebClient.Builder
然后根据需要调用其方法。WebClient.Builder
实例是有状态的:生成器上的任何更改都会反映在随后使用它创建的所有客户端中。
如果要使用同一个构建器创建多个客户端,还可以考虑使用WebClient.Builder other = builder.clone();
.
要对所有应用程序进行 Additive 自定义WebClient.Builder
实例中,你可以声明WebClientCustomizer
beans 并将WebClient.Builder
注射点局部。
最后,您可以回退到原始 API 并使用WebClient.create()
.
在这种情况下,没有自动配置或WebClientCustomizer
。
7. Web 服务
Spring Boot 提供了 Web 服务自动配置,因此您所要做的就是定义您的Endpoints
.
Spring Web 服务功能可以通过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
使用 Classpath 上可用的 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 通过使用 Atomikos 嵌入式事务管理器支持跨多个 XA 资源的分布式 JTA 事务。 部署到合适的 Java EE Application Server 时,也支持 JTA 事务。
当检测到 JTA 环境时, Spring 的JtaTransactionManager
用于管理事务。
自动配置的 JMS、DataSource 和 JPA bean 已升级以支持 XA 事务。
您可以使用标准的 Spring 惯用语,例如@Transactional
参与分布式事务。
如果您在 JTA 环境中,并且仍希望使用本地事务,则可以设置spring.jta.enabled
property 设置为false
以禁用 JTA 自动配置。
8.1. 使用 Atomikos 事务管理器
Atomikos 是一种流行的开源事务管理器,可以嵌入到 Spring Boot 应用程序中。
您可以使用spring-boot-starter-jta-atomikos
starter 拉取适当的 Atomikos 库。
Spring Boot 会自动配置 Atomikos 并确保适当的depends-on
设置将应用于 Spring bean,以实现正确的启动和关闭顺序。
默认情况下,Atomikos 事务日志会写入transaction-logs
目录。
您可以通过设置spring.jta.log-dir
属性包含在application.properties
文件。
属性以spring.jta.atomikos.properties
也可以用来定制 AtomikosUserTransactionServiceImp
.
请参阅AtomikosProperties
Javadoc了解完整详情。
为了确保多个事务管理器可以安全地协调相同的资源管理器,必须为每个 Atomikos 实例配置一个唯一的 ID。
默认情况下,此 ID 是运行 Atomikos 的计算机的 IP 地址。
为了确保生产中的唯一性,您应该配置spring.jta.transaction-manager-id 属性,该属性具有不同的值。 |
8.2. 使用 Java EE Managed Transaction Manager
如果您将 Spring Boot 应用程序打包为war
或ear
文件并将其部署到 Java 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.3. 混合 XA 和非 XA JMS 连接
使用 JTA 时,主 JMSConnectionFactory
bean 是 XA 感知的,并参与分布式事务。
您可以注入到 bean 中,而无需使用任何@Qualifier
:
public MyBean(ConnectionFactory connectionFactory) {
// ...
}
在某些情况下,您可能希望使用非 XA 处理某些 JMS 消息ConnectionFactory
.
例如,您的 JMS 处理逻辑可能比 XA 超时花费的时间更长。
如果要使用非 XAConnectionFactory
,您可以nonXaJmsConnectionFactory
豆:
public MyBean(@Qualifier("nonXaJmsConnectionFactory") ConnectionFactory connectionFactory) {
// ...
}
为了保持一致性,jmsConnectionFactory
bean 也是通过使用 bean 别名提供的xaJmsConnectionFactory
:
public MyBean(@Qualifier("xaJmsConnectionFactory") ConnectionFactory connectionFactory) {
// ...
}
8.4. 支持替代的嵌入式事务管理器
这XAConnectionFactoryWrapper
和XADataSourceWrapper
接口可用于支持替代的嵌入式事务管理器。
接口负责包装XAConnectionFactory
和XADataSource
bean 并将它们公开为常规ConnectionFactory
和DataSource
bean,它们以透明方式注册分布式事务。
DataSource 和 JMS 自动配置使用 JTA 变体,前提是您有一个JtaTransactionManager
bean 和相应的 XA 包装器 bean 中注册的ApplicationContext
.
AtomikosXAConnectionFactoryWrapper 和 AtomikosXADataSourceWrapper 提供了如何编写 XA 包装器的良好示例。