Spring Cloud是构建分布式系统的工具集,它基于Spring Boot,提供了一系列解决分布式系统常见问题的框架。Spring Cloud专注于为典型的分布式系统用例提供良好的开箱即用体验,如配置管理、服务发现、熔断器、智能路由、微代理、控制总线等。
Spring Cloud的核心优势:
微服务架构是一种将应用程序构建为一组小型服务的架构风格。这些服务围绕业务能力构建,可以通过自动化部署机制独立部署,服务之间的通信通常采用轻量级HTTP API。
Spring Cloud与微服务的关系:
Spring Cloud自2014年发布以来,经历了多个版本迭代,主要版本历程如下:
值得注意的是,Spring Cloud的版本命名从字母顺序(如Angel、Brixton)转变为年份命名(如2020.x),这反映了其发展方向的变化和对云原生环境的更深入支持。
Spring Cloud的技术体系非常丰富,包括多个子项目,每个子项目解决特定的问题:
这些组件形成了一个完整的生态系统,使开发者能够根据需要选择适合的工具来构建分布式系统。
优点:
缺点:
微服务拆分是微服务架构设计中最关键的步骤之一,常见的拆分策略包括:
微服务拆分建议:
领域驱动设计(Domain-Driven Design, DDD)是一种软件开发方法,非常适合微服务架构设计。
DDD核心概念:
限界上下文(Bounded Context):定义了模型的边界,确保模型在特定上下文中的一致性
领域模型(Domain Model):反映业务领域核心概念和规则的对象模型
聚合(Aggregate):一组相关对象的集合,作为一个整体对外提供一致性保证
领域事件(Domain Event):领域中发生的重要事件,可以用于服务间通信
DDD在微服务架构中的应用:
示例:电商系统的DDD分析
订单上下文(Order Context):
- 聚合:订单(Order)、订单项(OrderItem)
- 领域事件:订单创建事件、订单支付事件、订单取消事件
商品上下文(Product Context):
- 聚合:商品(Product)、库存(Inventory)
- 领域事件:库存变更事件、商品更新事件
用户上下文(User Context):
- 聚合:用户(User)、地址(Address)
- 领域事件:用户注册事件、用户信息更新事件
Eureka是Netflix开发的服务注册与发现框架,是Spring Cloud中最常用的服务发现组件之一。
Eureka采用C/S架构,由以下两个组件组成:
Eureka的基本工作流程:
Eureka支持高可用部署,多个Eureka Server之间相互注册形成集群:
# Eureka Server 1 (node1)
server:
port: 8761
eureka:
instance:
hostname: eureka-server1
client:
serviceUrl:
defaultZone: http://eureka-server2:8762/eureka/,http://eureka-server3:8763/eureka/
# Eureka Server 2 (node2)
server:
port: 8762
eureka:
instance:
hostname: eureka-server2
client:
serviceUrl:
defaultZone: http://eureka-server1:8761/eureka/,http://eureka-server3:8763/eureka/
# Eureka Server 3 (node3)
server:
port: 8763
eureka:
instance:
hostname: eureka-server3
client:
serviceUrl:
defaultZone: http://eureka-server1:8761/eureka/,http://eureka-server2:8762/eureka/
Eureka有一个名为"自我保护模式"的特性,当Eureka Server在短时间内丢失过多客户端时(可能是网络分区故障),它会进入自我保护模式,保留所有服务实例信息,而不是将不可用的实例删除。
自我保护模式的配置:
eureka:
server:
enable-self-preservation: true # 启用自我保护模式(默认)
renewal-percent-threshold: 0.85 # 自我保护阈值,默认0.85
eureka:
client:
register-with-eureka: true # 是否注册到Eureka Server
fetch-registry: true # 是否从Eureka Server获取注册信息
registry-fetch-interval-seconds: 30 # 获取注册信息的间隔时间
service-url:
defaultZone: http://localhost:8761/eureka/ # Eureka Server地址
instance:
lease-renewal-interval-in-seconds: 30 # 心跳间隔
lease-expiration-duration-in-seconds: 90 # 服务过期时间
instance-id: ${spring.application.name}:${server.port} # 实例ID
prefer-ip-address: true # 使用IP地址而不是主机名
metadata-map: # 元数据,可以存储自定义信息
zone: zone1
version: v1
Eureka中的服务实例(Instance)有多种状态:
可以通过配置更改实例状态:
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private EurekaClient eurekaClient;
// 获取所有服务
List services = discoveryClient.getServices();
// 将服务实例设置为OUT_OF_SERVICE状态
eurekaClient.getApplicationInfoManager()
.setInstanceStatus(InstanceStatus.OUT_OF_SERVICE);
Eureka Server:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
// EurekaServerApplication.java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
# application.yml
spring:
application:
name: eureka-server
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: true
eviction-interval-timer-in-ms: 60000 # 清理间隔(毫秒)
Eureka Client:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
// ServiceApplication.java
@SpringBootApplication
@EnableEurekaClient // 也可以使用@EnableDiscoveryClient
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
# application.yml
spring:
application:
name: sample-service
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 90
注意: Spring Cloud 2020及以后的版本,@EnableEurekaClient
注解已不再必需,只要添加了Eureka Client依赖并配置好服务地址,服务就会自动注册到Eureka Server。
Nacos是阿里巴巴开发的服务发现和配置管理平台,Spring Cloud Alibaba将其集成到Spring Cloud生态中。Nacos不仅提供服务发现功能,还提供配置管理功能,是一个更加综合的解决方案。
Nacos采用集中式架构,主要包括以下组件:
Nacos的基本工作流程:
Nacos支持集群部署以保证高可用:
集群模式需要配置cluster.conf
文件,列出所有Nacos节点:
# cluster.conf
192.168.0.1:8848
192.168.0.2:8848
192.168.0.3:8848
Nacos集群还需要外部数据库(MySQL)存储数据:
# application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config
db.user=nacos
db.password=nacos
Nacos的服务发现具有以下特性:
1. 添加依赖:
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2. 配置Nacos Server地址:
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: public # 命名空间ID
group: DEFAULT_GROUP # 分组
cluster-name: DEFAULT # 集群名
register-enabled: true # 是否注册
ephemeral: true # 是否临时实例
weight: 1 # 权重
3. 启用服务发现:
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现客户端
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1. 命名空间(Namespace):
命名空间用于隔离服务,通常用于区分不同环境(开发、测试、生产)或不同租户。
spring:
cloud:
nacos:
discovery:
namespace: 9e83dc5c-2a8f-4e73-b996-c6633a683888 # 命名空间ID
2. 分组(Group):
分组用于将服务进行逻辑分组,通常根据业务分类。
spring:
cloud:
nacos:
discovery:
group: PAY_GROUP # 支付服务组
3. 临时实例与持久实例:
Nacos支持两种类型的实例:
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为持久实例
4. 使用权重进行负载均衡:
可以为每个实例设置权重,权重越大,分配到的请求越多。
spring:
cloud:
nacos:
discovery:
weight: 2 # 权重为2
5. 使用元数据进行版本控制:
可以使用元数据定义服务版本,并配合负载均衡策略进行版本路由。
spring:
cloud:
nacos:
discovery:
metadata:
version: v1
env: prod
1. 启动Nacos Server:
# 下载Nacos
wget https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.zip
# 解压
unzip nacos-server-2.0.3.zip
# 启动(单机模式)
cd nacos/bin
sh startup.sh -m standalone
2. 创建服务提供者:
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
// ProviderApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
// UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return new User(id, "用户" + id);
}
}
# application.yml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
server:
port: 8080
3. 创建服务消费者:
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-loadbalancer
// ConsumerApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
// UserClient.java
@Service
public class UserClient {
@Autowired
private RestTemplate restTemplate;
public User getUserById(Long id) {
return restTemplate.getForObject("http://user-service/users/" + id, User.class);
}
}
// OrderController.java
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private UserClient userClient;
@GetMapping("/{orderId}/user")
public User getUserByOrderId(@PathVariable Long orderId) {
// 假设orderId对应的订单所属的用户ID为orderId+1
return userClient.getUserById(orderId + 1);
}
}
# application.yml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
server:
port: 8081
Consul是HashiCorp开发的服务发现和配置管理解决方案,与Eureka、Nacos不同,它是使用Go语言编写的,并提供了一个功能齐全的控制平面,具有服务发现、健康检查、KV存储、多数据中心、安全服务通信等功能。
Consul集群由多个节点组成,节点分为Server和Client两种角色:
Consul使用Gossip协议管理成员关系、广播消息,并使用Raft协议实现一致性。
1. 添加依赖:
org.springframework.cloud
spring-cloud-starter-consul-discovery
2. 配置Consul:
spring:
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
instance-id: ${spring.application.name}:${random.value}
health-check-path: /actuator/health
health-check-interval: 15s
3. 启用服务发现:
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Zookeeper是Apache软件基金会的一个项目,是一个分布式协调服务,也可以用作服务注册中心。
1. 添加依赖:
org.springframework.cloud
spring-cloud-starter-zookeeper-discovery
2. 配置Zookeeper:
spring:
cloud:
zookeeper:
connect-string: localhost:2181
discovery:
register: true
root: /services
prefer-ip-address: true
3. 启用服务发现:
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
选择适合的注册中心需要考虑多个因素,以下是主流注册中心的比较:
特性 | Eureka | Nacos | Consul | Zookeeper |
---|---|---|---|---|
开发语言 | Java | Java | Go | Java |
CAP特性 | AP | CP+AP | CP | CP |
健康检查 | 客户端心跳 | TCP/HTTP/MySQL/自定义 | TCP/HTTP/gRPC/自定义 | 客户端心跳 |
负载均衡 | 客户端 | 客户端/服务端 | 客户端/服务端 | 客户端 |
自动注销实例 | 支持 | 支持 | 支持 | 支持 |
访问协议 | HTTP | HTTP/DNS | HTTP/DNS | TCP |
监听支持 | 支持 | 支持 | 支持 | 支持 |
多数据中心 | 不支持 | 支持 | 支持 | 不支持 |
SpringCloud集成 | 原生支持 | 通过Spring Cloud Alibaba | 原生支持 | 原生支持 |
界面 | 一般 | 较好 | 较好 | 无 |
社区活跃度 | 低(已停止开发) | 高 | 高 | 中 |
选择建议:
Ribbon是Netflix开发的客户端负载均衡器,可以与Eureka等服务发现组件集成,实现服务消费者的负载均衡。
Ribbon负载均衡的基本工作流程:
Ribbon在客户端完成负载均衡,整个过程对服务提供者透明。
通过@LoadBalanced
注解,RestTemplate可以集成Ribbon实现负载均衡:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 使用时直接用服务名替代主机名和端口
@Autowired
private RestTemplate restTemplate;
public User getUser(Long id) {
return restTemplate.getForObject("http://user-service/users/" + id, User.class);
}
Ribbon提供了多种负载均衡策略,可以根据需要选择:
配置负载均衡策略:
方式一:使用配置类
@Configuration
public class RibbonConfig {
@Bean
public IRule ribbonRule() {
return new RandomRule(); // 使用随机策略
}
}
方式二:使用配置文件
user-service: # 服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectTimeout: 1000
ReadTimeout: 3000
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 1
OkToRetryOnAllOperations: true
Ribbon提供了超时和重试机制,可以通过配置文件设置:
ribbon:
ConnectTimeout: 1000 # 连接超时时间(ms)
ReadTimeout: 5000 # 读取超时时间(ms)
MaxAutoRetries: 1 # 同一实例最大重试次数,不包括首次调用
MaxAutoRetriesNextServer: 1 # 切换实例的最大重试次数
OkToRetryOnAllOperations: false # 是否所有操作都重试
注意:如果启用了Hystrix,还需要确保Hystrix的超时时间大于Ribbon的超时时间,否则Hystrix会提前中断请求。
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
可以通过实现IRule
接口自定义负载均衡策略:
public class CustomRule extends AbstractLoadBalancerRule {
@Override
public Server choose(Object key) {
List servers = getLoadBalancer().getAllServers();
// 实现自定义选择逻辑
// 例如:根据服务器CPU负载、内存使用率等选择
// 或者根据请求的特定参数选择服务实例
if (servers.isEmpty()) {
return null;
}
// 简单实现:优先选择第10个请求的服务器为首选
int serverCount = servers.size();
int index = 0;
if (key instanceof Integer) {
int requestId = (Integer) key;
if (requestId % 10 == 0) {
index = requestId % serverCount;
} else {
index = new Random().nextInt(serverCount);
}
} else {
index = new Random().nextInt(serverCount);
}
return servers.get(index);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// 初始化配置
}
}
注册自定义策略:
@Configuration
public class RibbonConfig {
@Bean
public IRule ribbonRule() {
return new CustomRule();
}
}
可以通过实现ClientHttpRequestInterceptor
接口自定义请求拦截器,添加请求头、日志等功能:
public class RibbonRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
// 添加请求头
request.getHeaders().add("X-Request-ID", UUID.randomUUID().toString());
// 记录请求日志
System.out.println("发起请求:" + request.getURI());
// 执行请求
long startTime = System.currentTimeMillis();
ClientHttpResponse response = execution.execute(request, body);
long endTime = System.currentTimeMillis();
// 记录响应日志
System.out.println("请求耗时:" + (endTime - startTime) + "ms");
return response;
}
}
注册拦截器:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(
Collections.singletonList(new RibbonRequestInterceptor())
);
return restTemplate;
}
}
Spring Cloud LoadBalancer是Ribbon的替代品,提供了基于Spring的负载均衡实现。由于Netflix Ribbon已经处于维护模式,Spring Cloud 2020版本后推荐使用Spring Cloud LoadBalancer。
1. 添加依赖:
org.springframework.cloud
spring-cloud-starter-loadbalancer
2. 启用LoadBalancer:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
使用WebClient:
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
// 使用
@Autowired
private WebClient.Builder webClientBuilder;
public Mono getUser(Long id) {
return webClientBuilder.build()
.get()
.uri("http://user-service/users/" + id)
.retrieve()
.bodyToMono(User.class);
}
LoadBalancer提供了多种配置选项:
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # 禁用Ribbon
cache:
enabled: true # 启用缓存
ttl: 30s # 缓存时间
retry:
enabled: true # 启用重试
LoadBalancer提供了以下负载均衡策略:
配置负载均衡策略:
@Configuration
public class LoadBalancerConfig {
@Bean
public ServiceInstanceListSupplier serviceInstanceListSupplier() {
return new DelegatingServiceInstanceListSupplier(
new DiscoveryClientServiceInstanceListSupplier(
new DiscoveryClientServiceInstanceListSupplier(null),
new RandomLoadBalancer()
)
);
}
}
或者使用更简洁的方式:
@Configuration
@LoadBalancerClient(name = "user-service", configuration = UserServiceConfig.class)
public class LoadBalancerConfig {
}
class UserServiceConfig {
@Bean
public ReactorLoadBalancer reactorLoadBalancer(
Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
name
);
}
}
可以通过实现ReactorServiceInstanceLoadBalancer
接口自定义负载均衡策略:
public class WeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final String serviceId;
private final ReactiveLoadBalancer.Factory loadBalancerFactory;
private final Random random;
public WeightedLoadBalancer(ReactiveLoadBalancer.Factory loadBalancerFactory,
String serviceId) {
this.serviceId = serviceId;
this.loadBalancerFactory = loadBalancerFactory;
this.random = new Random();
}
@Override
public Mono> choose(Request request) {
ServiceInstanceListSupplier supplier = loadBalancerFactory
.getLazyProvider(serviceId, ServiceInstanceListSupplier.class)
.getIfAvailable();
return supplier.get().next()
.map(instances -> getInstanceResponse(instances, request));
}
private Response getInstanceResponse(
List instances, Request request) {
if (instances.isEmpty()) {
return new EmptyResponse();
}
// 根据权重选择实例
// 假设每个实例有一个"weight"元数据
int totalWeight = 0;
Map weights = new HashMap<>();
for (ServiceInstance instance : instances) {
int weight = 1; // 默认权重
if (instance.getMetadata().containsKey("weight")) {
weight = Integer.parseInt(instance.getMetadata().get("weight"));
}
weights.put(instance, weight);
totalWeight += weight;
}
int randomWeight = random.nextInt(totalWeight) + 1;
int current = 0;
for (Map.Entry entry : weights.entrySet()) {
current += entry.getValue();
if (randomWeight <= current) {
return new DefaultResponse(entry.getKey());
}
}
// 默认返回第一个实例
return new DefaultResponse(instances.get(0));
}
}
注册自定义策略:
@Configuration
@LoadBalancerClient(name = "user-service", configuration = UserServiceConfig.class)
public class LoadBalancerConfig {
}
class UserServiceConfig {
@Bean
public ReactorLoadBalancer reactorLoadBalancer(
Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new WeightedLoadBalancer(loadBalancerClientFactory, name);
}
}
不同的负载均衡策略适用于不同的场景,了解各策略的优缺点有助于选择合适的策略。
原理:按照顺序依次选择服务实例
优点:
缺点:
适用场景:服务实例性能相近,且无特殊需求时
原理:随机选择一个服务实例
优点:
缺点:
适用场景:请求量大,服务实例性能相近时
原理:根据实例的平均响应时间计算权重,响应时间越短权重越大
优点:
缺点:
适用场景:服务实例性能差异大,或者部署环境异构时
原理:优先选择与消费者相同区域的服务实例
优点:
缺点:
适用场景:多数据中心或多可用区部署时
原理:选择当前并发请求数最少的实例
优点:
缺点:
适用场景:请求处理时间差异大,或服务实例容易过载时
设计自定义负载均衡策略时,可以考虑以下因素:
RestTemplate是Spring提供的用于访问Rest服务的客户端,它提供了多种便捷访问远程HTTP服务的方法,是Spring Cloud中实现服务间调用的基础工具之一。
1. 创建RestTemplate:
@Bean
@LoadBalanced // 启用负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
2. 常用方法:
// GET请求
// 返回对象
User user = restTemplate.getForObject("http://user-service/users/{id}", User.class, 1);
// 返回包含响应信息的对象
ResponseEntity response = restTemplate.getForEntity("http://user-service/users/{id}", User.class, 1);
// POST请求
// 返回对象
User newUser = new User("张三", 25);
User result = restTemplate.postForObject("http://user-service/users", newUser, User.class);
// 返回包含响应信息的对象
ResponseEntity response = restTemplate.postForEntity("http://user-service/users", newUser, User.class);
// 返回新创建资源的URI
URI location = restTemplate.postForLocation("http://user-service/users", newUser);
// PUT请求
User user = new User(1L, "李四", 30);
restTemplate.put("http://user-service/users/{id}", user, 1);
// DELETE请求
restTemplate.delete("http://user-service/users/{id}", 1);
// 交换请求(可用于任何HTTP方法)
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity entity = new HttpEntity<>(user, headers);
ResponseEntity response = restTemplate.exchange(
"http://user-service/users/{id}",
HttpMethod.PUT,
entity,
User.class,
1
);
// 执行请求
ResponseEntity response = restTemplate.execute(
"http://user-service/users/{id}",
HttpMethod.GET,
request -> {
// 请求前处理
request.getHeaders().add("X-Custom-Header", "value");
},
response -> {
// 响应处理
return ResponseEntity.ok(response.getBody());
},
1
);
1. 连接超时和读取超时:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 连接超时5秒
factory.setReadTimeout(5000); // 读取超时5秒
return new RestTemplate(factory);
}
2. 错误处理:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getStatusCode() == HttpStatus.NOT_FOUND) {
// 处理404错误
throw new ResourceNotFoundException("资源不存在");
} else {
super.handleError(response);
}
}
});
return restTemplate;
}
3. 消息转换器:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 添加自定义的消息转换器
List> converters = restTemplate.getMessageConverters();
// 添加FastJSON转换器
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
converters.add(0, fastConverter); // 添加到首位
return restTemplate;
}
可以添加拦截器实现请求/响应日志、认证等功能:
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
// 记录请求信息
logger.info("Request URI: {}", request.getURI());
logger.info("Request Method: {}", request.getMethod());
logger.info("Request Headers: {}", request.getHeaders());
// 执行请求
long startTime = System.currentTimeMillis();
ClientHttpResponse response = execution.execute(request, body);
long endTime = System.currentTimeMillis();
// 记录响应信息
logger.info("Response Status: {}", response.getStatusCode());
logger.info("Response Time: {}ms", (endTime - startTime));
return response;
}
}
添加拦截器:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 添加拦截器
restTemplate.setInterceptors(
Collections.singletonList(new LoggingInterceptor())
);
return restTemplate;
}
RestTemplate可以与服务发现组件(如Eureka、Nacos)集成,通过服务名调用服务:
@Bean
@LoadBalanced // 关键注解,启用负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 使用服务名调用
User user = restTemplate.getForObject("http://user-service/users/{id}", User.class, 1);
@LoadBalanced
注解的作用:
LoadBalancerInterceptor
拦截器,拦截所有RestTemplate请求@Service
public class UserServiceClient {
private final RestTemplate restTemplate;
private fina