本文目录导读:

- 理解一:微服务架构中的“服务跟随用户”(Session Affinity / 粘性会话)
- 理解二:客户端与服务端的“伴随服务”(Companion Service / Sidecar)
- 理解三:终端用户设备的“随行服务”(跨设备/跨平台同步)
- 总结:选择哪种实现?
“服务随行”这个术语在Java开发中通常有几种不同的含义,取决于具体的业务场景,为了给你最准确的答案,我列举了最常见的三种理解,并附上相应的Java实现案例。
请根据你的实际需求选择对应的方案:
微服务架构中的“服务跟随用户”(Session Affinity / 粘性会话)
场景:在分布式系统中,用户登录后,请求需要一直落在同一台服务器上,或者用户信息能在不同服务间传递。 核心实现:使用 JWT(JSON Web Token)或 Redis Session。
案例:基于 JWT 的 Token 透传
用户登录后,网关将一个包含用户信息的Token(JWT)注入到后续所有微服务的请求头中。
// 1. 用户登录成功,生成JWT
// 依赖:io.jsonwebtoken:jjwt
public String generateToken(String userId, String permissions) {
return Jwts.builder()
.setSubject(userId)
.claim("permissions", permissions)
.setExpiration(new Date(System.currentTimeMillis() + 3600_000)) // 1小时过期
.signWith(SignatureAlgorithm.HS256, "your-secret-key")
.compact();
}
// 2. 在微服务网关的过滤器中,将Token透传给下游服务(以Spring Cloud Gateway为例)
public GatewayFilter applyUserTokenFilter() {
return (exchange, chain) -> {
// 从请求头或Cookie中取出Token
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token != null && token.startsWith("Bearer ")) {
// 将Token添加到下游请求头,以便下游服务解析
ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
.header("X-User-Token", token)
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
return chain.filter(exchange);
};
}
// 3. 下游服务解析Token,获取用户信息
public String getCurrentUserId(String token) {
Claims claims = Jwts.parser()
.setSigningKey("your-secret-key")
.parseClaimsJws(token.replace("Bearer ", ""))
.getBody();
return claims.getSubject(); // 获取用户ID
}
核心逻辑:将用户上下文(UserId)编码进Token,服务间调用时携带该Token,实现状态“随行”。
客户端与服务端的“伴随服务”(Companion Service / Sidecar)
场景:传统老旧系统或非Java应用(如Python、Go)需要接入微服务体系(如注册、监控)。 核心实现:使用 Spring Cloud Sidecar 或 Netflix Prana。
案例:使用 Spring Cloud Sidecar 代理非Java服务
假设你有一个用Go写的服务(端口8081),你想让它接入Eureka注册中心。
<!-- 1. 在Sidecar项目中引入依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-sidecar</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
# 2. application.yml 配置
spring:
application:
name: go-sidecar # 注册到Eureka的服务名
server:
port: 5678 # Sidecar代理端口
sidecar:
port: 8081 # 真实Go服务的HTTP端口
health-uri: http://localhost:8081/health # 健康检查端点
hostname: localhost
ip-address: 127.0.0.1
// 3. 启动类开启@EnableSidecar
@SpringBootApplication
@EnableSidecar
public class SidecarApplication {
public static void main(String[] args) {
SpringApplication.run(SidecarApplication.class, args);
}
}
核心逻辑:Sidecar作为一个“随身代理”,负责将非Java服务的健康检查、注册、发现等功能纳入Java微服务体系。
终端用户设备的“随行服务”(跨设备/跨平台同步)
场景:用户在手机端操作了一半,切换到PC端后数据不丢失,流程可继续。 核心实现:消息推送 + 无状态化设计 + Redis缓存。
案例:购物车或办事流程随行
用户将商品加入A手机的购物车,用同一账号登录B电脑后,购物车内容依然存在。
// 1. 添加商品到购物车(服务端存储,而非客户端)
public void addToCart(String userId, CartItem item) {
// 使用Redis存储,key为 user:cart:123
String key = "user:cart:" + userId;
redisTemplate.opsForHash().put(key, item.getSkuId(), item);
// 如果用户在线,推送通知(例如使用WebSocket)
String deviceId = getUserActiveDevice(userId); // 获取当前活跃设备ID
if (deviceId != null) {
websocketService.sendMessage(deviceId, "您的购物车已更新");
}
}
// 2. 另一端登录时拉取数据
public List<CartItem> syncCartOnLogin(String userId, String newDeviceId) {
String key = "user:cart:" + userId;
// 直接从Redis读取全部商品
List<CartItem> items = redisTemplate.opsForHash().values(key);
// 如果用户之前在其他设备操作未完成(如订单草稿),一并同步
String draftKey = "user:draft:" + userId;
OrderDraft draft = redisTemplate.opsForValue().get(draftKey);
if (draft != null) {
// 将草稿推送给新设备
websocketService.sendMessage(newDeviceId, draft);
}
return items;
}
核心逻辑:服务端保持状态(Redis/数据库),而非客户端,用户切换终端时,自动从服务端拉取最新状态。
选择哪种实现?
| 业务需求 | Java核心技术 | 推荐方案 |
|---|---|---|
| 用户登录态跨服务 | JWT / OAuth2 / Spring Security | Token透传 |
| 旧系统接入微服务 | Sidecar / 适配器模式 | Sidecar |
| 用户跨设备操作 | 无状态化设计 + 推送(WebSocket) | 服务端存储 |
如果你能补充更具体的业务场景(例如是在局域网内设备联动,还是在云端分布式系统间同步),我可以给出更有针对性的代码架构建议。