安徽省建设监理网站,创意设计作品欣赏,成免费的crm无需下载,天津市工程建设公众信息网官网RPC概述
思考#xff1a; 微服务之间如何方便优雅的实现服务间的远程调用#xff1f; RPC 全称是 Remote Procedure Call #xff0c;即远程过程调用#xff0c;其对应的是我们的本地调用。RPC 的目的是#xff1a;让我们调用远程方法像调用本地方法一样。
//本地调用
R…RPC概述
思考 微服务之间如何方便优雅的实现服务间的远程调用 RPC 全称是 Remote Procedure Call 即远程过程调用其对应的是我们的本地调用。RPC 的目的是让我们调用远程方法像调用本地方法一样。
//本地调用
R result orderService.findOrderByUserId(id);
//RPC远程调用 orderService为代理对象
R result orderService.findOrderByUserId(id);RPC框架设计架构 什么是Feign
Feign是Netflix开发的声明式、模板化的HTTP客户端Feign可帮助我们更加便捷、优雅地调用HTTP API。
Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验开发者完全感知不到这是远程方法更感知不到这是个 HTTP 请求。它像 Dubbo 一样consumer 直接调用接口方法调用 provider而不需要通过常规的 Http Client 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样无需关注与远程的交互细节更无需关注分布式环境开发。
Spring Cloud openfeign对Feign进行了增强使其支持Spring MVC注解另外还整合了Ribbon和Eureka从而使得Feign的使用更加方便。
RibbonFeign对比
RibbonRestTemplate进行微服务调用
Bean
LoadBalanced
public RestTemplate restTemplate() {return new RestTemplate();
}//调用方式
String url http://mall-order/order/findOrderByUserId/id;
R result restTemplate.getForObject(url,R.class);Feign进行微服务调用
FeignClient(value mall-order,path /order)
public interface OrderFeignService {RequestMapping(/findOrderByUserId/{userId})public R findOrderByUserId(PathVariable(userId) Integer userId);
}Autowired
OrderFeignService orderFeignService;
//feign调用
R result orderFeignService.findOrderByUserId(id);Feign的设计架构 Spring Cloud Alibaba快速整合Feign
1引入依赖
!-- openfeign 远程调用 --
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId
/dependency2编写调用接口FeignClient注解
FeignClient(value mall-order,path /order)
public interface OrderFeignService {RequestMapping(/findOrderByUserId/{userId})public R findOrderByUserId(PathVariable(userId) Integer userId);
}3调用端在启动类上添加EnableFeignClients注解
SpringBootApplication
EnableFeignClients //扫描和注册feign客户端的beanDefinition
public class MallUserFeignDemoApplication {public static void main(String[] args) {SpringApplication.run(MallUserFeignDemoApplication.class, args);}
}4发起调用像调用本地方式一样调用远程服务
RestController
RequestMapping(/user)
public class UserController {AutowiredOrderFeignService orderFeignService;RequestMapping(value /findOrderByUserId/{id})public R findOrderByUserId(PathVariable(id) Integer id) {//feign调用R result orderFeignService.findOrderByUserId(id);return result;}
}提示 Feign 的继承特性可以让服务的接口定义单独抽出来作为公共的依赖以方便使用。
Spring Cloud Feign扩展
Feign 提供了很多的扩展机制让用户可以更加灵活的使用。 日志配置 有时候我们遇到 Bug比如接口调用失败、参数没收到等问题或者想看看调用性能就需要配置 Feign 的日志了以此让 Feign 把请求信息输出来。 1定义一个配置类指定日志级别
// 注意 此处配置Configuration注解就会全局生效如果想指定对应微服务生效就不能配置Configuration
Configuration
public class FeignConfig {/*** 日志级别** return*/Beanpublic Logger.Level feignLoggerLevel() {return Logger.Level.FULL;}
}通过源码可以看到日志等级有 4 种分别是
NONE【性能最佳适用于生产】不记录任何日志默认值。BASIC【适用于生产环境追踪问题】仅记录请求方法、URL、响应状态代码以及执行时间。HEADERS记录BASIC级别的基础上记录请求和响应的header。FULL【比较适用于开发及测试环境定位问题】记录请求和响应的header、body和元数据。 局部配置让调用的微服务生效在FeignClient 注解中指定使用的配置类 在yml配置文件中配置 Client 的日志级别才能正常输出日志格式是logging.level.feign接口包路径debug
logging:level:com.tuling.mall.feigndemo.feign: debug测试BASIC级别日志
补充局部配置可以在yml中配置 对应属性配置类 org.springframework.cloud.openfeign.FeignClientProperties.FeignClientConfiguration
feign:client:config:mall-order: #对应微服务loggerLevel: FULL契约配置
Spring Cloud 在 Feign 的基础上做了扩展可以让 Feign 支持 Spring MVC 的注解来调用。原生的 Feign 是不支持 Spring MVC 注解的如果你想在 Spring Cloud 中使用原生的注解方式来定义客户端也是可以的通过配置契约来改变这个配置Spring Cloud 中默认的是 SpringMvcContract。
1修改契约配置支持Feign原生的注解
/*** 修改契约配置支持Feign原生的注解* return*/
Bean
public Contract feignContract() {return new Contract.Default();
}注意修改契约配置后OrderFeignService 不再支持springmvc的注解需要使用Feign原生的注解
2OrderFeignService 中配置使用Feign原生的注解
FeignClient(value mall-order,path /order)
public interface OrderFeignService {RequestLine(GET /findOrderByUserId/{userId})public R findOrderByUserId(Param(userId) Integer userId);
}3补充也可以通过yml配置契约
feign:client:config:mall-order: #对应微服务loggerLevel: FULLcontract: feign.Contract.Default #指定Feign原生注解契约配置通过拦截器实现参数传递
通常我们调用的接口都是有权限控制的很多时候可能认证的值是通过参数去传递的还有就是通过请求头去传递认证信息比如 Basic 认证方式。
Feign 中我们可以直接配置 Basic 认证
Configuration // 全局配置
public class FeignConfig {Beanpublic BasicAuthRequestInterceptor basicAuthRequestInterceptor() {return new BasicAuthRequestInterceptor(fox, 123456);}
}扩展点 feign.RequestInterceptor 每次 feign 发起http调用之前会去执行拦截器中的逻辑。
public interface RequestInterceptor {/*** Called for every request. Add data using methods on the supplied {link RequestTemplate}.*/void apply(RequestTemplate template);
}使用场景:
统一添加 header 信息对 body 中的信息做修改或替换
自定义拦截器实现认证逻辑
public class FeignAuthRequestInterceptor implements RequestInterceptor {Overridepublic void apply(RequestTemplate template) {// 业务逻辑String access_token UUID.randomUUID().toString();template.header(Authorization,access_token);}
}Configuration // 全局配置
public class FeignConfig {Beanpublic Logger.Level feignLoggerLevel() {return Logger.Level.FULL;}/*** 自定义拦截器* return*/Beanpublic FeignAuthRequestInterceptor feignAuthRequestInterceptor(){return new FeignAuthRequestInterceptor();}
}测试
补充可以在yml中配置
feign:client:config:mall-order: #对应微服务requestInterceptors[0]: #配置拦截器com.tuling.mall.feigndemo.interceptor.FeignAuthRequestInterceptor
mall-order端可以通过 RequestHeader获取请求参数建议在filter,interceptor中处理超时时间配置
通过 Options 可以配置连接超时时间和读取超时时间Options 的第一个参数是连接的超时时间ms默认值是 2s第二个是请求处理的超时时间ms默认值是 5s。 全局配置
Configuration
public class FeignConfig {Beanpublic Request.Options options() {return new Request.Options(5000, 10000);}
}yml中配置
feign:client:config:mall-order: #对应微服务# 连接超时时间默认2sconnectTimeout: 5000# 请求处理超时时间默认5sreadTimeout: 10000补充说明 Feign的底层用的是Ribbon但超时时间以Feign配置为准 测试超时情况
返回结果
客户端组件配置 Feign 中默认使用 JDK 原生的 URLConnection 发送 HTTP 请求我们可以集成别的组件来替换掉 URLConnection比如 Apache HttpClientOkHttp。 Feign发起调用真正执行逻辑feign.Client#execute 扩展点
配置Apache HttpClient 引入依赖
!-- Apache HttpClient --
dependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpclient/artifactIdversion4.5.7/version
/dependency
dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-httpclient/artifactIdversion10.1.0/version
/dependency然后修改yml配置将 Feign 的 Apache HttpClient启用
feign:#feign 使用 Apache HttpClient 可以忽略默认开启httpclient:enabled: true 关于配置可参考源码 org.springframework.cloud.openfeign.FeignAutoConfiguration
测试调用会进入feign.httpclient.ApacheHttpClient#execute
配置 OkHttp
引入依赖
dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-okhttp/artifactId
/dependency然后修改yml配置将 Feign 的 HttpClient 禁用启用 OkHttp配置如下
feign:#feign 使用 okhttphttpclient:enabled: falseokhttp:enabled: true关于配置可参考源码 org.springframework.cloud.openfeign.FeignAutoConfiguration
测试调用会进入feign.okhttp.OkHttpClient#execute
GZIP 压缩配置 开启压缩可以有效节约网络资源提升接口性能我们可以配置 GZIP 来压缩数据
feign:# 配置 GZIP 来压缩数据compression:request:enabled: true# 配置压缩的类型mime-types: text/xml,application/xml,application/json# 最小压缩值min-request-size: 2048response:enabled: true注意只有当 Feign 的 Http Client 不是 okhttp3 的时候压缩才会生效配置源码在FeignAcceptGzipEncodingAutoConfiguration
核心代码就是 ConditionalOnMissingBeantype“okhttp3.OkHttpClient”表示 Spring BeanFactory 中不包含指定的 bean 时条件匹配也就是没有启用 okhttp3 时才会进行压缩配置。
编码器解码器配置
Feign 中提供了自定义的编码解码器设置同时也提供了多种编码器的实现比如 Gson、Jaxb、Jackson。我们可以用不同的编码解码器来处理数据的传输。如果你想传输 XML 格式的数据可以自定义 XML 编码解码器来实现获取使用官方提供的 Jaxb。
扩展点Encoder Decoder
public interface Encoder {void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException;
}
public interface Decoder {Object decode(Response response, Type type) throws IOException, DecodeException, FeignException;
}Java配置方式
配置编码解码器只需要在 Feign 的配置类中注册 Decoder 和 Encoder 这两个类即可:
Bean
public Decoder decoder() {return new JacksonDecoder();
}
Bean
public Encoder encoder() {return new JacksonEncoder();
}
yml配置方式
feign:client:config:mall-order: #对应微服务# 配置编解码器encoder: feign.jackson.JacksonEncoderdecoder: feign.jackson.JacksonDecoderSpring Cloud整合Dubbo
provider端配置
1引入依赖
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-dubbo/artifactIdversion2.2.7.RELEASE/version
/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId
/dependency注意因为spring cloud alibaba 2.2.8这个版本没有整合dubbo所以需要指定dubbo的版本
2修改application.yml
dubbo:scan:# 指定 Dubbo 服务实现类的扫描基准包base-packages: com.tuling.mall.user.service
# application:
# name: ${spring.application.name}protocol:# dubbo 协议name: dubbo# dubbo 协议端口 -1 表示自增端口从 20880 开始port: -1
# registry:
# #挂载到 Spring Cloud 注册中心 高版本可选
# address: spring-cloud://127.0.0.1:8848spring:application:name: spring-cloud-dubbo-provider-usermain:# Spring Boot2.1及更高的版本需要设定allow-bean-definition-overriding: truecloud:nacos:# Nacos 服务发现与注册配置discovery:server-addr: 127.0.0.1:88483服务实现类上配置DubboService暴露服务
DubboService
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;Overridepublic ListUser list() {return userMapper.list();}Overridepublic User getById(Integer id) {return userMapper.getById(id);}
}3.2 consumer端配置 1引入依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-dubbo/artifactIdversion2.2.7.RELEASE/version
/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId
/dependency2修改application.yml
dubbo:cloud:# 指定需要订阅的服务提供方默认值*会订阅所有服务不建议使用subscribed-services: spring-cloud-dubbo-provider-user
# application:
# name: ${spring.application.name}protocol:# dubbo 协议name: dubbo# dubbo 协议端口 -1 表示自增端口从 20880 开始port: -1
# registry:
# #挂载到 Spring Cloud 注册中心 高版本可选
# address: spring-cloud://127.0.0.1:8848spring:application:name: spring-cloud-dubbo-consumer-usermain:# Spring Boot2.1及更高的版本需要设定allow-bean-definition-overriding: truecloud:nacos:# Nacos 服务发现与注册配置discovery:server-addr: 127.0.0.1:8848当应用使用属性dubbo.cloud.subscribed-services为默认值时日志中将会输出警告
3服务消费方通过DubboReference引入服务
RestController
RequestMapping(/user)
public class UserConstroller {DubboReferenceprivate UserService userService;RequestMapping(/info/{id})public User info(PathVariable(id) Integer id){return userService.getById(id);}RequestMapping(/list)public ListUser list(){return userService.list();}
}从Open Feign迁移到Dubbo
Dubbo Spring Cloud 提供了方案可以从Open Feign迁移到Dubbo即 DubboTransported 注解。能够帮助服务消费端的 Spring Cloud Open Feign 接口以及 LoadBalanced RestTemplate Bean 底层走 Dubbo 调用可切换 Dubbo 支持的协议而服务提供方则只需在原有 RestController 类上追加 Dubbo Servce 注解需要抽取接口即可换言之在不调整 Feign 接口以及 RestTemplate URL 的前提下实现无缝迁移。
1修改服务提供者
DubboService
Slf4j
RestController
RequestMapping(/user)
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;OverrideRequestMapping(/list)public ListUser list() {log.info(查询user列表);return userMapper.list();}OverrideRequestMapping(/getById/{id})public User getById(PathVariable(id) Integer id) {return userMapper.getById(id);}
}2服务消费端引入依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-dubbo/artifactIdversion2.2.7.RELEASE/version
/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId
/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId
/dependency3添加Feign的实现启动类上添加EnableFeignClients
SpringBootApplication
EnableFeignClients
public class SpringCloudDubboConsumerUserFeignApplication {public static void main(String[] args) {SpringApplication.run(SpringCloudDubboConsumerUserFeignApplication.class, args);}}4Feign接口添加 DubboTransported 注解
FeignClient(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);
}FeignClient(value spring-cloud-dubbo-provider-user-feign,path /user)
public interface UserFeignService {RequestMapping(/list)public ListUser list();RequestMapping(/getById/{id})public User getById(PathVariable(id) Integer id);
}5调用对象添加 DubboTransported 注解发起调用
RestController
RequestMapping(/user)
public class UserConstroller {DubboReferenceprivate UserService userService;RequestMapping(/info/{id})public User info(PathVariable(id) Integer id){return userService.getById(id);}Autowiredprivate UserFeignService userFeignService;RequestMapping(/list)public ListUser list(){return userFeignService.list();}Autowiredprivate UserDubboFeignService userDubboFeignService;RequestMapping(/list2)public ListUser list2(){return userDubboFeignService.list();}}