springCloud alibaba实战三之OpenFeign(远程调用)

OpenFeign就是springCloud中的组件,一个优雅的远程调用组件,内部集成了ribbon负载均衡,我前期的博客貌似又写过它的集中负载方式,以及自定义负载
实例化restTemplater,自定义负载机制,如果要了解springCloud的创建过程,请转到这篇博客

@Configuration
public class ConfigBeans {
     //boot -->spring   applicationContext.xml --- @Configuration配置   ConfigBean = applicationContext.xml
        @Bean
        @LoadBalanced//Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端       负载均衡的工具。
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
    @Bean
    public IRule myRule()
    {
        //return new RoundRobinRule();//该策略实现安装线性轮询的方式依次选择每个服务实例
        return new RandomRule();//该策略实现安随机算法,
        //return new RetryRule();//具备重试机制的实例选择功能morning采用的轮训
    }
}

这里就不多说了,直接进入feign的打开方式
接着上一篇博客的故事开始
springCloud官网
springCloud中文文档
openFeign源码及文档

在公共项目中sca-common创建feign文件夹,专门用来对外暴露接口,供其他服务调用
在这里插入图片描述
创建BalanceFeignService,准备在account-service模块中调用balance-service的接口
注解@FeignClient的属性

name = "payment-service"   #被调用的服务名/
fallback = BalanceFeignService.BalanceFeignServiceFallback.class #服务出错时,调用该类的方法, 服务降级类
qualifier="paymentService" #限定服务调用名称,就是起了给名字
configuration = ServiceFeignConfiguration.class #feign的配置类,比如超时 等等

其他属性请自行去了解,
内部类中记得加@Component注解,以便能被spring扫描加载
代码

package com.hc.scacommon.feign;

import com.hc.scacommon.pojo.Balance;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
//qualifier="paymentService",
//configuration = ServiceFeignConfiguration.class,
@FeignClient(name = "payment-service", fallback = BalanceFeignService.BalanceFeignServiceFallback.class)
public interface BalanceFeignService {

    //远程调用
    @RequestMapping(value = "/pay/balance", method = RequestMethod.GET)
    Balance getBalance(@RequestParam("id") Integer id);

    //请求不到,则转入降级
    @Component
    class BalanceFeignServiceFallback implements BalanceFeignService {
        @Override
        public Balance getBalance(Integer id) {
            return new Balance(0, 0, 0, "服务降级,该服务已下线");
        }
    }
}

创建子项目account-service
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.hc</groupId>
        <artifactId>sca-parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.hc</groupId>
    <artifactId>account-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>account-service</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
        <alibaba.version>0.9.0.RELEASE</alibaba.version>
        <spring-cloud-netflix.version>2.1.1.RELEASE</spring-cloud-netflix.version>
        <spring-cloud-openfeign.version>2.1.1.RELEASE</spring-cloud-openfeign.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.hc</groupId>
            <artifactId>sca-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${alibaba.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${alibaba.version}</version>
        </dependency>

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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-openfeign-dependencies</artifactId>
                <version>${spring-cloud-openfeign.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

bootstrap.yml

spring:
  application:
    name: account-service
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848

application.yml

spring:
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
server:
  port: 8081

feign:
  client:
    config:
      default:         #default默认所有服务的超时时间
        connect-timeout: 10000
        read-timeout: 20000
#      payment-service:     #指定payment-service这个服务的超时时间
#        connect-timeout: 10000
#        read-timeout: 20000

controller

package com.hc.accountservice.controller;

import com.hc.scacommon.feign.BalanceFeignService;
import com.hc.scacommon.pojo.Balance;
import com.hc.scacommon.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class AccountController {

    //@Qualifier("paymentService")
    @Autowired
    private BalanceFeignService balanceFeignService;

    final static Map<Integer, User> userMap = new HashMap() {{
        put(1, new User(1, "张三"));
        put(2, new User(2, "李四"));
        put(3, new User(3, "王五"));
    }
    };

    @RequestMapping("/acc/user")
    public User getUser(@RequestParam Integer id) {
        if(id != null && userMap.containsKey(id)) {
            User user = userMap.get(id);
            Balance balance = balanceFeignService.getBalance(id);

            if(balance != null){
                user.setBalance(balance);
            }
            return user;
        }
        return new User(0, "");
    }
}

启动类

package com.hc.accountservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class AccountServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(AccountServiceApplication.class, args);
    }

}

启动类的注解少了点东西, 这里是个巨坑, 这里先卖个关子

启动两个服务
注意注意----接下来踩坑
当你启动account-service的时候报错
Field balanceFeignService in com.hc.accountservice.controller.AccountController required a bean of type 'com.hc.scacommon.feign.BalanceFeignService' that could not be found.
BalanceFeignService没有被发现, 意思是BalanceFeignService没有被加载
将@EnableFeignClients注解改为如下,将扫描com.hc.scacommon.feign这个包

@EnableFeignClients(basePackages= {"com.hc.scacommon.feign"})

在这里插入图片描述
重新启动account-service
莫慌, 还报错
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accountController': Unsatisfied dependency expressed through field 'balanceFeignService';
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.hc.scacommon.feign.BalanceFeignService': FactoryBean threw exception on object creation;
nested exception is java.lang.IllegalStateException: No fallback instance of type class com.hc.scacommon.feign.BalanceFeignService$BalanceFeignServiceFallback found for feign client payment-service
创建bean错误,通过字段“balanceFeignService”表示的未满足依赖项, 又是这个类
看最后一句错误: 找不到用于外部客户端payment-service的com.hc.scacommon.feign.BalanceFeignService$BalanceFeignService fallback类型的回退实例,找不到BalanceFeignService fallback这个实例, 这个内部类未被加载, 为什么呢

分析一下原因:
feign这个包在sca-common中被引入到account-service, 明明加了注解@Component的呀
错就错在你不熟悉springBoot的@SpringBootApplication这个注解
这个启动类注解扫描包的时候,只能扫描到该包,以及该包下的子包, 平级包都扫描不到
现在我们看看account-service启动类所在的包
在这里插入图片描述
再看看BalanceFeignService这个类在sca-common的包路径
在这里插入图片描述
BalanceFeignService跟启动类都不在一个包下面, 怎么可能扫描的到, 怎么可能被加载,
解决办法:

@SpringBootApplication(scanBasePackages = {"com.hc.accountservice", "com.hc.scacommon.feign"})

重新启动,完美解决
在这里插入图片描述
balance的信息来自feign服务调用
在这里插入图片描述
接下来验证feign集成ribbon负载
ribbon源码及文档
将payment-service以不同端口启动两个实例, 不知如何启动两个payment-service,请查看上一篇博文
多访问几次http://localhost:8081/acc/user?id=3, 会有轮询效果, 没有做ribbon的配置,默认就是轮询
这里我测试了7次
在这里插入图片描述
在这里插入图片描述
改变轮询策略
修改account-service的配置application.yml配置文件,添加:

payment-service:  #指定payment-service这个服务的负载策略,也可以不用这一级,直接下面的配置 代表所有
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule #配置规则 重试
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略
    ConnectTimeout: 500 #请求连接超时时间
    ReadTimeout: 1000 #请求处理的超时时间
    OkToRetryOnAllOperations: true #对所有请求都进行重试
    MaxAutoRetriesNextServer: 2 #切换实例的重试次数
    MaxAutoRetries: 1 #对当前实例的重试次数

#ribbon:
  #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
  #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
  #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule #配置规则 重试
  #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
  #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略
  #ConnectTimeout: 500 #请求连接超时时间
  #ReadTimeout: 1000 #请求处理的超时时间
  #OkToRetryOnAllOperations: true #对所有请求都进行重试
  #MaxAutoRetriesNextServer: 2 #切换实例的重试次数
  #MaxAutoRetries: 1 #对当前实例的重试次数

这里我配置的随机策略
在这里插入图片描述
在这里插入图片描述
其他模式,请自行测试
接下来说一下熔断,降级功能, 我上面的feign中已经写了payment-service这个服务的降级功能
现在我们来测试一下, 关掉payment-service的两个服务
然后访问http://localhost:8081/acc/user?id=3, 看能否降级成功
在这里插入图片描述
在这里插入图片描述
明显报错,没有payment-service这个客户端,降级失败
这个时候该alibaba的sentinel登场了, 现在我就不细讲他的作用了,下一篇博客我会细讲他的作用
alibaba之sentinel文档
修改account-service的application.yml配置文件,在feign下添加sentinel配置

feign:
  sentinel:
    enabled: true

添加sentinel依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>${alibaba.version}</version>
</dependency>

启动account-service,关闭其他服务,再次访问http://localhost:8081/acc/user?id=3
在这里插入图片描述
降级成功
至此feign远程调用,ribbon负载均衡,sentinel熔断服务降级,已经搭建并测试完毕
下一篇alibaba之sentinel

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值