Fegin在spring Cloud开发中的实际应用

思考

刚开始在学习feign的时候,各位是不是都把feginClient的代码写到服务调用方?我相信网上百分之99在教程里面都是这么写的。但在实际应用中如果这么写会带来哪些问题?

  • 有N个调用方就要写N个FeginClient。
  • 如果服务提供商接口变动(当然这个应该很少变动,但不能说一定不),所有的服务调用方都需要改动代码,而且你得通知到每个服务调用方的具体变动内容(比如接口参数变了还是参数类型变了,这样调用方才知道怎么改)。
    其实这样已经很明显了,我们应该把FeginClient的代码写到服务提供方,这样上面的问题就会变成优点。
    ps:先把demo放到一开始吧,本来想放到最后的,但是担心有些大佬觉得我啰嗦,就先放到前面来

提供什么内容

根据上面思考,我们已经知道FeginClient是卸载服务提供方的工程中。那么具体的服务提供商中需要提供什么内容呢?
首先FeginClient和FeginClientFallBack的代码是需要提供的,FeginClient中是可能需要实体类,因此服务方的实体类也是需要的,那么服务商的业务逻辑需要么(比如controller、service、dao)?这需要个xxx啊,调用方关心服务方的业务逻辑么?那当然不关心啦。
因此:我们需要在服务方中把FeginClient和FeginClientFallBack以及实体类的信息单体提供出来。

以什么方式来提供

既然我们都用了maven方式了,那么我么可以以maven项目的方式引入呀,其实也就是所谓的api包。

实际应用

1 工程中新建maven项目

项目右键->module->maven项目
Fegin在spring Cloud开发中的实际应用_第1张图片
输入项目名称cloud-order-api,选择parent是cloud-order
Fegin在spring Cloud开发中的实际应用_第2张图片为了专业,我们单独给业务逻辑新建一个maven项目,叫做cloud-order-biz业务逻辑层。具体和上面一样的。这里就不截图了。我放上最后的完整的项目结构:

Fegin在spring Cloud开发中的实际应用_第3张图片

  1. 然后我们在aip包中新建2个类,一个是feginClient类和FallBack类。直接贴代码了,没啥好说的,如果你是从一个简单的 springCloud 入门实例(一)这边文章过来的话,就直接移动文件就行了,都是一样的。

FeginClient 类

@FeignClient(name = "cloud-order-biz",fallback = TestFallBack.class)
public interface OrderRemoteClient1 {

    @GetMapping("/makeOrder")
    String makeOrder(@RequestParam("name") String userName);

}

TestFallBack类

@Component
public class TestFallBack implements OrderRemoteClient1 {
    @Override
    public String makeOrder(String userName) {
        return "出错了";
    }
}
  1. biz中新建一个OrderController
@RestController
public class OrderController {

    @GetMapping("/makeOrder")
    public String makeOrder(@RequestParam("name") String userName) {
 //       throw new RuntimeException("服务端测试异常!");
        return userName + "下单成功";
    }
}

到此为止,一个简单的服务提供方已经完成了,只要调用方中引入包,然后直接调用makeOrder方法,就可以实现远程调用的方法。

2 服务方引入api模块

  1. 引入pom文件
		<dependency>
            <groupId>com.cjgroupId>
            <artifactId>cloud-order-apiartifactId>
            <version>0.0.1-SNAPSHOTversion>
            <scope>compilescope>
        dependency>
  1. 在需要使用的地方直接利用注解注入:
@RestController
@EnableFeignClients
@SpringBootApplication
@EnableDiscoveryClient
public class CloudUserApplication {

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

    @Value("${heheda}")
    private String config;
    @Autowired
    private OrderRemoteClient1 orderRemoteClient1;


    @GetMapping("/helloNacos")
    public String helloNacos() {
        System.out.println("当前实例------> A" + orderRemoteClient1.makeOrder("caojinger"));
        return "你好,nacos!";
    }
}

这边简单介绍下注解的作用:

  • @EnableFeignClients开启远程调用。
  • @EnableDiscoveryClient开启服务的注册与发现。
    ok,启动项目~

3 出现的问题以及解决方案

1.0 FeginClient无法注入

不出意外的话,你应该启动不起来,如果你是按照我这样做的话,肯定是起不来的。会报如下的错误:
Fegin在spring Cloud开发中的实际应用_第4张图片这个错误也很好理解,就是OrderRemoteClient1没有注入成功。是不是很奇怪?那我们就是要想办法把OrderRemoteClient1纳入到spirngboot的ioc容器中。
这边需要关注一个注解:@EnableFeignClients
想想之前,FeignClient写在调用方的时候,也只是加了这个注解,也没有写什么@Compoment这种注解。
那么唯一的解释就是:@EnableFeignClients注解帮我们自动扫描到@FeignClient标记的实体类,并且自动注入到ioc容器中。
那现在为什么不行了呢?我们可以查看下@EnableFeignClients的源代码:其中有个参数:basePackages引起了我的注意:
Fegin在spring Cloud开发中的实际应用_第5张图片

1.1 解决方案

所以,我们这边给basePackage加一个值:

@EnableFeignClients(basePackages = {"com.cj.cloud.order"})

com.cj.cloud.order就是自己的包名。
我们先来看下有没有解决这个问题,启动项目,启动成功,页面访问地址:http://localhost:8080/helloNacos
Fegin在spring Cloud开发中的实际应用_第6张图片
Fegin在spring Cloud开发中的实际应用_第7张图片
问题已经解决了。

1.2 总结

为什么会出现这个问题:很简单,之前我们把FeignClient写在调用方的时候,都是在同一个包下,这个道理其实和@SpringBootApplication的道理是一样的,会加载当前Application所在的包的路径。
换成maven依赖导入之后,我们调用方的包路径是:com.cj.cloud.user而api包的包路径是com.cj.cloud.order,这很明显就扫描不到@FeginClient注解的类,从而导致注入失败。

2.0 熔断机制无法触发

突然心血来潮,想试试异常熔断机制有没有生效。把OrderController类改成如下所示:

@RestController
public class OrderController {

    @GetMapping("/makeOrder")
    public String makeOrder(@RequestParam("name") String userName) {
        throw new RuntimeException("服务端测试异常!");
//        return userName + "下单成功";
    }
}

重启cloud-order-biz工程,页面访问http://localhost:8080/helloNacos,出现如下所示页面:
Fegin在spring Cloud开发中的实际应用_第8张图片
这代表什么?这特喵的代表熔断没有生效啊,贼尴尬。解决了一波问题又来了一波问题,谁知道把FeginClient改成依赖包这么麻烦呢=。=。
既然没有生效,那我们应该要去解决这个问题,为什么熔断机制没有生效?
注意看 TestFallBack类上的@Component注解,这个注解大家熟悉吧?那么我想问下大家,这个注解在以api包依赖以后,这个注解有用么?会自动注入到项目的ioc容器中去么?答案是:不会。这个道理和上面的问题是一样的。
@SpringBootApplication只会扫描当前包下的加了需要注解的类。

2.1 解决方案

我给大家介绍三种解决方案,具体用法,按照个人喜好来吧

  • 把api包的包名改成和项目一样的路径(但是这种仅限于内部系统使用,约定大于-配置)
  • @SpringBootApplication注解中也有scanBasePackages参数,把api的包路径写到这个参数里面即可。
  • 利用spring.factories自动注入实体类。

笔者这边推荐大家使用第三种方式来注入,因为前2种或多或少都对服务调用方有一定的限制。
cloud-order-api项目的resource文件夹下面新建一个文件META-INF,然后在文件中新增一个名字叫做spring.factories的文件,文件内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.cj.cloud.order.api.TestFallBack

解释一下:

@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。

Fegin在spring Cloud开发中的实际应用_第9张图片
两个项目都重新启动,页面访问http://localhost:8080/helloNacos
Fegin在spring Cloud开发中的实际应用_第10张图片
Fegin在spring Cloud开发中的实际应用_第11张图片
这就很完美了。服务提供方报错了,但是没有影响到服务调用方的逻辑,这才是正确的熔断机制。

这里还有一个坑,如果说这样你还是无法进入到TestFallBack方法的话,那么你需要检查一下配置中心的配置,springcloud是默认不开启熔断机制的,所以你需要开启熔断机制。
配置中心开启熔断机制
配置中心开启熔断机制
配置中心开启熔断机制

feign:
  hystrix:
    enabled: true
feign:
  hystrix:
    enabled: true
feign:
  hystrix:
    enabled: true

总结

这里我们把Fegin移动到服务提供方以后,看起来很简单,其中其中有很多需要注意的点以及可能会出现的问题。这些问题主要是集中在当以外部类提供到springboot项目中去的时候,需要把一些自动注入的类先在spring.factories文件中进行自动注入。一些未扫描到的实体类,需要在特定的注解中指定扫描包的路径。最后,各位大佬如果看的开心,麻烦点个关注、点个赞。
如果想了解一下spring Cloud入门的话, 可以看下我的这篇文章:
一个简单的 springCloud 入门实例(一)

你可能感兴趣的:(Spring,Cloud,Alibaba,spring,spring,boot,spring,cloud,alibaba,spring,cloud)