核心内容摘要
瑞古德漫画官方入口:开启你的次元奇幻之旅!
RPC调用基础与微服务通信挑战
1 RPC概述远程过程调用Remote Procedure CallRPC是微服务架构中的核心技术之一其核心目标是让远程方法调用像本地方法调用一样简单透明。
对比传统HTTP调用RPC提供了更高效的通信机制和更自然的调用体验。
java// 本地调用 R result orderService.findOrderByUserId(id); // RPC远程调用外观如同本地调用 R result orderService.findOrderByUserId(id);
2 微服务通信的演进从早期的HTTP Client手动封装到Spring Cloud提供的RestTemplateRibbon组合再到声明式的Feign客户端最后到高性能的Dubbo框架微服务间调用技术不断演进向着更高效、更便捷的方向发展。
Feign声明式HTTP客户端
1 什么是FeignFeign是Netflix开发的声明式、模板化HTTP客户端Spring Cloud对其进行了增强整合。
Feign的核心优势在于声明式API通过接口注解定义HTTP请求无需手动构建请求与Spring MVC无缝集成支持Spring MVC注解内置负载均衡自动整合Ribbon或LoadBalancer服务发现集成与Eureka、Nacos等服务注册中心完美配合
2 Feign vs RibbonRestTemplate传统方式RibbonRestTemplatejavaBean LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } // 调用方式 String url http://mall-order/order/findOrderByUserId/ id; R result restTemplate.getForObject(url, R.class);Feign方式声明式调用javaFeignClient(value mall-order, path /order) public interface OrderFeignService { RequestMapping(/findOrderByUserId/{userId}) public R findOrderByUserId(PathVariable(userId) Integer userId); } // 调用如同本地方法 Autowired OrderFeignService orderFeignService; R result orderFeignService.findOrderByUserId(id);
3 Feign设计架构Feign通过动态代理技术实现声明式调用其核心流程如下动态代理生成基于接口生成代理实现类注解解析解析接口方法上的Spring MVC注解请求模板构建根据解析结果构建RequestTemplate编码器处理通过Encoder将参数编码为请求体拦截器链执行RequestInterceptor拦截器链HTTP客户端执行通过配置的HTTP客户端发送请求响应解码通过Decoder将响应解码为返回对象
4 Spring Cloud快速整合Feign
引入依赖xmldependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-openfeign/artifactId /dependency
定义Feign客户端接口javaFeignClient(value mall-order, path /order) public interface OrderFeignService { RequestMapping(/findOrderByUserId/{userId}) public R findOrderByUserId(PathVariable(userId) Integer userId); }
启用Feign客户端javaSpringBootApplication EnableFeignClients public class MallUserFeignDemoApplication { public static void main(String[] args) { SpringApplication.run(MallUserFeignDemoApplication.class, args); } }
注入并使用javaRestController RequestMapping(/user) public class UserController { Autowired OrderFeignService orderFeignService; RequestMapping(value /findOrderByUserId/{id}) public R findOrderByUserId(PathVariable(id) Integer id) { // 像调用本地方法一样调用远程服务 R result orderFeignService.findOrderByUserId(id); return result; } }
5 Feign高级配置与扩展日志配置Feign提供四种日志级别便于调试和问题排查yaml# 配置日志级别 logging: level: com.tuling.mall.feigndemo.feign: debugjavaConfiguration public class FeignConfig { Bean public Logger.Level feignLoggerLevel() { return Logger.Level.FULL; // NONE, BASIC, HEADERS, FULL } }契约配置支持原生Feign注解javaBean public Contract feignContract() { return new Contract.Default(); // 使用Feign原生注解 } // 接口中使用原生注解 FeignClient(value mall-order, path /order) public interface OrderFeignService { RequestLine(GET /findOrderByUserId/{userId}) public R findOrderByUserId(Param(userId) Integer userId); }请求拦截器实现认证、参数传递javapublic class FeignAuthRequestInterceptor implements RequestInterceptor { Override public void apply(RequestTemplate template) { // 添加认证头信息 String accessToken UUID.randomUUID().toString(); template.header(Authorization, accessToken); } } Configuration public class FeignConfig { Bean public FeignAuthRequestInterceptor feignAuthRequestInterceptor() { return new FeignAuthRequestInterceptor(); } }超时时间配置yamlfeign: client: config: mall-order: connectTimeout: 5000 # 连接超时时间默认2s readTimeout: 10000 # 读取超时时间默认5sHTTP客户端配置Feign支持多种HTTP客户端默认使用JDK原生HttpURLConnection可切换为Apache HttpClient或OkHttpApache HttpClient配置yamlfeign: httpclient: enabled: trueOkHttp配置yamlfeign: httpclient: enabled: false okhttp: enabled: trueGZIP压缩配置yamlfeign: compression: request: enabled: true mime-types: text/xml,application/xml,application/json min-request-size: 2048 response: enabled: true编码器解码器配置yamlfeign: client: config: mall-order: encoder: feign.jackson.JacksonEncoder decoder: feign.jackson.JacksonDecoder
Dubbo高性能RPC框架
1 Spring Cloud整合DubboProvider端配置
引入依赖xmldependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-dubbo/artifactId version
2.
2.
RELEASE/version /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency
配置文件application.ymlyamldubbo: scan: base-packages: com.tuling.mall.user.service # Dubbo服务扫描包 protocol: name: dubbo port: -1 # 自增端口从20880开始 spring: application: name: spring-cloud-dubbo-provider-user main: allow-bean-definition-overriding: true cloud: nacos: discovery: server-addr:
127.
0.
1:
服务实现类javaDubboService public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; Override public ListUser list() { return userMapper.list(); } Override public User getUserId(Integer id) { return userMapper.getById(id); } }Consumer端配置
引入依赖同上
配置文件application.ymlyamldubbo: cloud: subscribed-services: spring-cloud-dubbo-provider-user # 订阅的服务 protocol: name: dubbo port: -1 spring: application: name: spring-cloud-dubbo-consumer-user main: allow-bean-definition-overriding: true cloud: nacos: discovery: server-addr:
127.
0.
1:
服务消费javaRestController RequestMapping(/user) public class UserController { DubboReference private UserService userService; RequestMapping(/info/{id}) public User info(PathVariable(id) Integer id) { return userService.getById(id); } RequestMapping(/list) public ListUser list() { return userService.list(); } }
2 从OpenFeign迁移到DubboSpring Cloud Alibaba提供了平滑迁移方案通过DubboTransported注解实现Feign接口底层走Dubbo调用
Provider端只需在原有RestController上添加DubboService注解javaDubboService Slf4j RestController RequestMapping(/user) public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; Override RequestMapping(/list) public ListUser list() { log.info(查询user列表); return userMapper.list(); } Override RequestMapping(/getById/{id}) public User getById(PathVariable(id) Integer id) { return userMapper.getById(id); } }
Consumer端Feign接口添加DubboTransported注解javaFeignClient(value spring-cloud-dubbo-provider-user-feign, path /user) DubboTransported(protocol dubbo) public interface UserDubboFeignService { RequestMapping(/list) public ListUser list(); RequestMapping(/getById/{id}) public User getById(PathVariable(id) Integer id); }
使用方式不变javaRestController RequestMapping(/user) public class UserController { Autowired private UserDubboFeignService userDubboFeignService; RequestMapping(/list
public ListUser list2() { return userDubboFeignService.list(); // 底层走Dubbo调用 } }
Feign与Dubbo对比与选型建议
1 技术对比特性FeignDubbo协议HTTP/REST多种协议dubbo、http等序列化JSON/XMLHessian
JSON、Java序列化等性能中等高性能服务治理依赖Spring Cloud生态内置完善的服务治理学习成本低基于Spring MVC中等适用场景微服务间HTTP调用高性能RPC调用、内部服务调用
2 选型建议新项目或RESTful架构优先考虑Feign与Spring Cloud生态整合更紧密性能要求高或内部服务调用考虑Dubbo性能优势明显混合架构可同时使用Feign和DubboFeign用于外部HTTP接口Dubbo用于内部高性能调用平滑迁移已有Feign项目可考虑通过DubboTransported逐步迁移到Dubbo
3 版本兼容性Spring Cloud Alibaba各版本组件兼容性Spring Cloud AlibabaSentinelNacosRocketMQDubboSeata
2.
2.
RELEASE
1.
8.
42.
1.
04.
3-
1.
5.
12021.
0.
1.
01.
8.
31.
4.
24.
2-
1.
4.
22.
2.
RELEASE
1.
8.
12.
0.
34.
6.
12.
7.
131.
0注意Spring Cloud Alibaba
2.
8版本未整合Dubbo如需使用Dubbo请选择
2.
7版本
总结微服务间的调用技术选型需要综合考虑性能需求、团队技术栈、生态系统整合等多方面因素。
Feign以其声明式的优雅设计和与Spring Cloud的深度整合成为RESTful调量的首选而Dubbo则以其高性能和完整的服务治理能力在高并发场景下展现出明显优势。
在实际项目中可以根据不同场景灵活选择对外提供REST API或调用第三方服务使用Feign内部高性能服务调用使用Dubbo已有项目迁移通过DubboTransported实现平滑过渡