crm开发定制SpringCloud-Gateway Feign

目录


一、Gateway简介

1.1 Gateway简介

Spring Cloud Gatewaycrm开发定制旨在提供一种简单而有crm开发定制效的方式来对API进行路由,crm开发定制并为他们提供切面,例如:安全性,监控/指标 和弹性等。

1.2 Gateway原理

客户端向spring-cloud-gatewaycrm开发定制请求网关映射处理程序(gateway handler mapping),crm开发定制如果确认请求与路由匹配,crm开发定制则将请求发送到web处理程序(gateway web handler),webcrm开发定制处理程序通过特定于该crm开发定制请求的过滤器链处理请求,图中filterscrm开发定制被虚线划分的原因是filterscrm开发定制可以在发送代理请求之前(pre filter)crm开发定制或之后执行逻辑(post filter)。crm开发定制先执行所有pre filter逻辑,crm开发定制然后进行请求代理。在请求代理执行完后,执行post filter逻辑。

二、Gateway程序案例

2.1 总体说明

本项目总体上为一个分步骤编写完成SpringCloud微服务开发项目的示例程序,使用了Eureka服务注册(第一步)、Ribbon请求负载均衡(第二步)和SpringCloud Gateway微服务网关(第三步)、完成统一服务接口调用(第四步)。
本案例说明为第三步:在前两步完成的基础上,引入SpringCloud-Gateway,通过网关统一调用服务。
本案例在第二步案例基础上,原有项目不做改变,只是新建了Gateway子项目,有变化的内容如图:

 注意:由于SpringCloud-Gateway是基于webflux的,它跟传统的springboot-mvc是冲突的,因此不需在其中排除springmvc相关包!

2.2 新建SpringCloud-Gateway子项目

1.在父项目中,新建子模块项目:new->Module依然选择maven项目。

本项目名称我们命名为Gateway。

2.配置pom.xml

依赖项配置如下:

  1. <dependencies>
  2. <!-- Eureka客户端 -->
  3. <dependency>
  4. <groupId>org.springframework.cloud</groupId>
  5. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  6. </dependency>
  7. <!-- SpringCloud网关Gateway -->
  8. <dependency>
  9. <groupId>org.springframework.cloud</groupId>
  10. <artifactId>spring-cloud-starter-gateway</artifactId>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.alibaba</groupId>
  14. <artifactId>fastjson</artifactId>
  15. </dependency>
  16. </dependencies>

注意:由于SpringCloud-Gateway是基于webflux的,它与spring boot mvc方式不兼容,启动Gateway会报错,因此不要引入spring-boot-starter-web依赖!

3.配置application.yml文件

Gateway项目也是一个Eureka客户端,并且需要SpringCloud-Gateway自身的配置:

  4.编写SpringBoot应用主类

2.3 结果验证

1.按顺序启动各个子项目

先启动EurekaService子项目,它是Eureka服务器,其他子模块都需作为Eureka客户端在它上面进行注册!
再启动Gateway、ServiceOne、ServiceOneCopy、ServiceTwo和ServiceThree,启动后如下图:

 2.进入Eureka服务状态页面,查看服务注册情况

在谷歌浏览器中输入:http://127.0.0.1:8000/,进入Eureka服务页面,我们查看当前注册情况:

 3.验证已有的各业务接口

在使用Gateway之后,所有的请求都应当通过Gateway来统一调用各个微服务业务模块的接口,根据Gateway的配置,调用形式统一为:
http://Gateway_HOST:Gateway_PORT/大写的serviceId/**
我们在浏览器地址栏或者PostMan中依次请求已存在的几个接口地址:

1)ServiceOne模块业务接口

http://127.0.0.1:8088/SERVICE-ONE/serviceOne

 由于ServiceOne和ServiceOneCopy都使用同一个应用ID:“service-one”,因此Gateway通过应用ID请求“serviceOne”接口时,已经自动进行了负载均衡,第二次重复调用的结果:

2)ServiceTwo模块业务接口

http://127.0.0.1:8088/SERVICE-TWO/serviceTwo

 3)ServiceThree模块业务接口(负载均衡)

 http://127.0.0.1:8088/SERVICE-THREE/serviceThree

 http://127.0.0.1:8088/SERVICE-THREE/serviceThree_toOne

第一次调用:

 第二次调用:

http://127.0.0.1:8088/SERVICE-THREE/serviceThree_toTwo

2.4 总结

        结论:通过Gateway作为服务网关,可统一调用其他微服务提供的业务接口!

        且Gateway会自动对映射为同一服务名称(应用ID)的模块中的相同接口进行负载均衡。

        另外,目前还可以通过各微服务子模块的具体业务地址,继续访问它的业务接口。这是因为SpringCloud-Gateway对于各子业务模块是“无感知”、“透明”的。将来需要在各模块添加认证拦截功能,可以保证未经认证的请求不能直接进入各微服务接口!(也可以通过运维手段只开放Gateway端口,其他微服务端口全部为内网端口)

三、openfeign简介

3.1 openfeign介绍

        Spring OpenFeign是一个轻量级的http请求调用框架。基于Netflix Feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix。Spring OpenFeign具有可插拔注解支持,包含Feign注解和JAX-RS注解,同时扩展了对Spring-MVC的注解支持。入参和请求都比较直观。Feign封装了HTTP调用流程,通过面向接口的方式,让微服务之间的接口调用变得简单,默认使用的是JDK的httpUrlConnection。 Feign是一个伪客户端,不会做任何的请求处理。

官方文档在这里

四、openfeign程序编写

4.1总体说明

本项目总体上为一个分步骤编写完成SpringCloud微服务开发项目的示例程序,使用了Eureka服务注册(第一步)、Ribbon请求负载均衡(第二步)和SpringCloud Gateway微服务网关(第三步)、Feign完成统一服务接口调用(第四步)
本案例说明为第四步:在前三步完成的基础上,引入Open Feign,通过在Gateway网关中统一调用服务接口(请求时不再出现各微服务名称)。
本案例在第三步案例基础上,原有项目不做改变,只是在Gateway子项目中引入OpenFeign并作相应配置,有变化的内容如图:

4.2 修改pom.xml引入OpenFeign的依赖

我们在原有Gateway子项目的pom.xml文件中,引入OpenFeign的依赖:

  1. <!-- feign依赖包 -->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-openfeign</artifactId>
  5. </dependency>

4.3 application.yml不做变化

本次使用Feign,无需改变application.yml配置文件!

4.4 修改主类,启用Feign

接下来,我们需要在SpringBootApplication的主类中启用Feign,给主类前添加“@EnableFeignClients”。

4.5 编写Feign接口

在Gateway项目增加feign包,再接下来,我们需要在项目feign包内编写要封装(内部调用其它微服务)的接口。

1.封装“SERVICE-ONE”接口

新增“ServiceOneFeign.java”文件,编写接口:

 2.封装“SERVICE-TWO”接口

新增“ServiceTwoFeign.java”文件,编写接口:

 3.封装“SERVICE-THREE”接口

新增“ServiceThreeFeign.java”文件,编写接口:

4.6 提供统一对外服务接口

最后,在Gateway中,编写对外统一提供服务的Controller接口,从此刻起外部只需要同意调用这些“统一形式的服务接口”即可,无需关心具体的微服务子模块了!
我们新增一个控制器“FeignUniformController”:

  1. package com.tjetc.controller;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.tjetc.feign.ServiceOneFeign;
  4. import com.tjetc.feign.ServiceThreeFeign;
  5. import com.tjetc.feign.ServiceTwoFeign;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. @RestController
  10. @RequestMapping("unifrom")
  11. public class FeignUniformController {
  12. @Autowired
  13. private ServiceOneFeign serviceOneFeign;
  14. @Autowired
  15. private ServiceTwoFeign serviceTwoFeign;
  16. @Autowired
  17. private ServiceThreeFeign serviceThreeFeign;
  18. @RequestMapping("serviceOne")
  19. public JSONObject serviceOne() {
  20. JSONObject serviceOneJson = serviceOneFeign.serviceOne();
  21. return serviceOneJson;
  22. }
  23. @RequestMapping("serviceTwo")
  24. public JSONObject serviceTwo() {
  25. JSONObject serviceTwoJson = serviceTwoFeign.serviceTwo();
  26. return serviceTwoJson;
  27. }
  28. @RequestMapping("serviceThree")
  29. public JSONObject serviceThree() {
  30. JSONObject serviceThreeJson = serviceThreeFeign.serviceThree();
  31. return serviceThreeJson;
  32. }
  33. @RequestMapping("serviceThree_toOne")
  34. public JSONObject serviceThreeToOne() {
  35. JSONObject serviceThreeToOneJson = serviceThreeFeign.serviceThreeToOne();
  36. return serviceThreeToOneJson;
  37. }
  38. @RequestMapping("serviceThree_toTwo")
  39. public JSONObject serviceThreeToTwo() {
  40. JSONObject serviceThreeToTwoJson = serviceThreeFeign.serviceThreeToTwo();
  41. return serviceThreeToTwoJson;
  42. }
  43. }

注意1:要把ServiceThree项目中api使用服务调用

注意2:由于springcloud的Gateway使用openfeign有错误,需要修正代码如下:

  1. package com.tjetc.configuration;
  2. import org.springframework.cloud.client.ServiceInstance;
  3. import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
  4. import org.springframework.cloud.client.loadbalancer.Request;
  5. import org.springframework.cloud.client.loadbalancer.Response;
  6. import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
  7. import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
  8. import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
  9. import reactor.core.publisher.Mono;
  10. import java.util.concurrent.CompletableFuture;
  11. import java.util.concurrent.ExecutionException;
  12. public class CustomBlockingLoadBalancerClient extends BlockingLoadBalancerClient {
  13. private final ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerClientFactory;
  14. public CustomBlockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory,
  15. LoadBalancerProperties properties) {
  16. super(loadBalancerClientFactory, properties);
  17. this.loadBalancerClientFactory = loadBalancerClientFactory;
  18. }
  19. public CustomBlockingLoadBalancerClient(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerClientFactory) {
  20. super(loadBalancerClientFactory);
  21. this.loadBalancerClientFactory = loadBalancerClientFactory;
  22. }
  23. @Override
  24. public <T> ServiceInstance choose(String serviceId, Request<T> request) {
  25. ReactiveLoadBalancer<ServiceInstance> loadBalancer =
  26. loadBalancerClientFactory.getInstance(serviceId);
  27. if (loadBalancer == null) {
  28. return null;
  29. }
  30. CompletableFuture<Response<ServiceInstance>> f =
  31. CompletableFuture.supplyAsync(() -> {
  32. Response<ServiceInstance> loadBalancerResponse =
  33. Mono.from(loadBalancer.choose(request)).block();
  34. return loadBalancerResponse;
  35. });
  36. Response<ServiceInstance> loadBalancerResponse = null;
  37. try {
  38. loadBalancerResponse = f.get();
  39. } catch (InterruptedException e) {
  40. e.printStackTrace();
  41. } catch (ExecutionException e) {
  42. e.printStackTrace();
  43. }
  44. if (loadBalancerResponse == null) {
  45. return null;
  46. }
  47. return loadBalancerResponse.getServer();
  48. }
  49. }
  1. package com.tjetc.configuration;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
  4. import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. @Configuration
  8. public class LoadBalancerClientConfig {
  9. @Autowired
  10. private LoadBalancerClientFactory loadBalancerClientFactory;
  11. @Bean
  12. public LoadBalancerClient blockingLoadBalancerClient() {
  13. return new CustomBlockingLoadBalancerClient(loadBalancerClientFactory);
  14. }
  15. }
  1. package com.tjetc.configuration;
  2. import feign.codec.Decoder;
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.ObjectFactory;
  5. import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
  6. import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
  7. import org.springframework.cloud.openfeign.support.SpringDecoder;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. import org.springframework.http.MediaType;
  11. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14. @Configuration
  15. public class FeignConfig {
  16. @Bean
  17. public Decoder feignDecoder() {
  18. return new ResponseEntityDecoder(new SpringDecoder(feignHttpMessageConverter()));
  19. }
  20. public ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
  21. final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(new GateWayMappingJackson2HttpMessageConverter());
  22. return new ObjectFactory<HttpMessageConverters>() {
  23. @Override
  24. public HttpMessageConverters getObject() throws BeansException {
  25. return httpMessageConverters;
  26. }
  27. };
  28. }
  29. public class GateWayMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
  30. GateWayMappingJackson2HttpMessageConverter() {
  31. List<MediaType> mediaTypes = new ArrayList<>();
  32. mediaTypes.add(MediaType.valueOf(MediaType.TEXT_HTML_VALUE + ";charset=UTF-8"));
  33. setSupportedMediaTypes(mediaTypes);
  34. }
  35. }
  36. }

4.7结果验证

1.按顺序启动各个子项目

先启动EurekaService子项目,它是Eureka服务器,其他子模块都需作为Eureka客户端在它上面进行注册!
再启动Gateway、ServiceOne、ServiceOneCopy、ServiceTwo和ServiceThree,启动后如下图:

 2.进入Eureka服务状态页面,查看服务注册情况

在谷歌浏览器中输入:http://127.0.0.1:8000/,进入Eureka服务页面,我们查看当前注册情况:

 

 3.验证新增统一服务接口

在引入Feign后,我们需要调用Gateway的统一服务接口,形式为:
http://Gateway_HOST:Gateway_PORT/feignUniform/**
我们在浏览器地址栏或者PostMan中依次请求封装好的几个接口地址:

1)unifrom/serviceOne(ServiceOne模块)业务接口

http://127.0.0.1:8088/unifrom/serviceOne

 由于ServiceOne和ServiceOneCopy都使用同一个应用ID:“service-one”,因此Gateway通过封装的请求“serviceOne”接口时,已经自动进行了负载均衡,第二次重复调用的结果:

2)feignUniform/serviceTwo(ServiceTwo模块)业务接口

http://127.0.0.1:8088/unifrom/serviceTwo

 3)feignUniform/serviceThree_toOne(ServiceThree模块,负载均衡)

http://127.0.0.1:8088/unifrom/serviceThree_toOne

第一次调用:

 第二次调用:

 4)http://127.0.0.1:8088/unifrom/serviceThree_toTwo

4.8 总结

结论:通过Gateway作为服务网关,我们已经做到统一调用其他微服务提供的业务接口。但需要在请求接口路径上添加各业务模块的应用名称,比如:
        http://127.0.0.1:8088/SERVICE-ONE/serviceOne
        http://127.0.0.1:8088/SERVICE-TWO/serviceTwo

在引入了Feign后,可以做到对外统一服务接口形式,因此暴露给外部的接口地址变为:
        http://127.0.0.1:8088/feignUniform/serviceOne
        http://127.0.0.1:8088/feignUniform/serviceTwo

外部系统再也无须获知内部的微服务信息了,从而做到了统一服务接口的封装(内部负载均衡)!

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发