风萧萧兮易水寒

Spring Cloud Eureka服务通信Ribbon/Feign(三)

问题

每一个客户端就是一个完整的项目,是一个模块,假如我有订单模块,支付模块,用户模块,等等,那么我这些模块之间怎么相互调用呢?采用HttpClient工具类访问?

Ribbon 和 Feign 简介

Ribbon 简介

Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出 Load Balancer 后面所有的机器,Ribbon 会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。简单地说,Ribbon 是一个客户端负载均衡器。

Feign 简介

Feign 是一个声明式的 web service 客户端,它使得编写 web service 客户端更为容易。创建接口,为接口添加注解,即可使用Feign。Feign可以使用Feign注解或者JAX-RS注解,还支持热插拔的编码器和解码器。Spring Cloud 为Feign添加了Spring MVC的注解支持,并整合了Ribbon和Eureka来为使用 Feign 时提供负载均衡。

创建支付模块(客户端)

起名pay项目,也可以去spring官网 https://start.spring.io/按照之前的办法创建
再介绍一个方法,直接在idea中创建

下一步

填写组织和项目名称

搜索添加

下一步

完成
然后按照客户端的修改操作进行修改
修改application.yml
因为是小demo,所以就不使用集群了,电脑有点卡。真实情况每个服务端和客户端有可能都不在一个服务器上

spring:
  application:
    name: pay
server:
  port: 8081
eureka:
  client:
    service-url:
      #注册中心路径,表示我们向这个注册中心注册服务,如果向多个注册中心注册,用“,”进行分隔
      #defaultZone: http://server01:8761/eureka/,http://server02:8762/eureka/
      defaultZone: http://server01:8761/eureka/

修改启动项
添加注解@EnableDiscoveryClient
添加一个正常情况下的最简洁支付接口

/**
 * @ Description   :  支付接口
 * @ Author        :  GMaya
 * @ CreateDate    :  2020/3/16 10:53
 * @ Version       :  1.0
 */
@RestController
public class PayController {
    @RequestMapping("/getPay")
    public String getPay(){
        // 返回支付信息
       return "this pay!!!";
    };

};

创建订单模块(客户端)

跟上面支付模块一模一样的操作。。。
注意:

创建订单最简洁订单的接口

/**
 * @ Description   :  订单接口
 * @ Author        :  GMaya
 * @ CreateDate    :  2020/3/16 11:03
 * @ Version       :  1.0
 */
@RestController
public class OrderController {
    @RequestMapping("/getOrder")
    public String getOrder(){
        // 返回订单信息
       return "this order!!!";
    };

};

此时两个正常的项目已经创建完毕,那么我订单模块怎么去调用支付模块呢?

方式一:RestTemplate调用

修改订单模块接口

 @RequestMapping("/getOrder")
    public String getOrder(){
        RestTemplate restTemplate = new RestTemplate();
        String forObject = restTemplate.getForObject("http://localhost:8081/getPay", String.class);
       return forObject;
    };

启动服务端,启动支付端,启动订单端
调用支付接口

调用订单接口

可以看出调用成功,但是缺点也很明显,必须要知道对方的url地址,对于多个实例那就难受了,所以是不可取的。

方式二:通过 @LoadBalanced

添加RestTemplateConfig配置

/**
 * @ Description   :  RestTemplate配置类
 * @ Author        :  GMaya
 * @ CreateDate    :  2020/3/16 11:24
 * @ Version       :  1.0
 */
@Component
public class RestTemplateConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    };
};


修改订单接口
此时只需要填写调用的项目名就好了,跟ip无关。

/**
 * @ Description   :  订单接口接口
 * @ Author        :  GMaya
 * @ CreateDate    :  2020/3/16 11:03
 * @ Version       :  1.0
 */
@RestController
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/getOrder")
    public String getOrder(){
        String forObject = restTemplate.getForObject("http://PAY/getPay", String.class);
        return forObject;
    };
};

重启订单项目查看


@LoadBalanced 源码
注解源码注释中说,用来标记restTemplate使之配置使用LoadBalancerClient

/**
 * Annotation to mark a RestTemplate or WebClient bean to be configured to use a
 * LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD };)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {

};

LoadBalancerClient则表示客户端负载均衡器。

所以使用@LoadBalanced就代表使用ribbon实现客户端的负载均衡
负载均衡的策略默认使用的是轮询算法

负载均衡是在同一个功能的微服务中根据不同的策略选择不同的微服务,因此这些微服务对外暴露的实例名称要相同(spring.application.name)
ribbon是一个客户端的负载均衡,必须要连接eureka,才能在指定的微服务实例中按照策略选择

假设支付模块(pay)部署在两台或者多台服务器,只有端口号不一样,其他的都一样,那么我订单模块按照轮询算法去调用支付模块。

方式三:通过 Feign

第一步:添加Feign依赖
打开订单模块pom文件

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

第二步:修改订单模块启动类OrderApplication
添加注解@EnableFeignClients

第三步:声明需要调用的接口
创建PayClient接口

/**
 * @ Description   :  支付接口声明
 * @ Author        :  GMaya
 * @ CreateDate    :  2020/3/16 14:28
 * @ Version       :  1.0
 */

@FeignClient(name = "pay") // 服务名称
public interface PayClient {
    @RequestMapping("/getPay") //  这里要和pay提供的接口一致
    String getPay();
};


修改OrderController

/**
 * @ Description   :  订单接口接口
 * @ Author        :  GMaya
 * @ CreateDate    :  2020/3/16 11:03
 * @ Version       :  1.0
 */
@RestController
public class OrderController {

    @Autowired
    private PayClient payClient; // 注入支付模块服务

    @RequestMapping("/getOrder")
    public String getOrder(){
        String pay = payClient.getPay();
        return pay;
    };
};

重启订单模块项目,一切正常!

只有先入门,才能追查源码以及骚操作!

坚持原创技术分享,您的支持将鼓励我继续创作!