> For the complete documentation index, see [llms.txt](https://taocares.gitbook.io/development-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://taocares.gitbook.io/development-guide/kai-fa-zhi-nan/fu-wu-tiao-yong.md).

# 服务调用

需要进行模块之间的服务调用时，使用Feign技术封装服务发现、负载均衡等细节，实现本地化形式的调用。

## 依赖

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

## 配置

开发者需要在入口类上配置`@EnableFeignClients`启用Feign的支持。

{% code title="DemoApplication.java" %}

```java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableSwagger2
@EnableDiscoveryClient
@EnableFeignClients
public class DemoApplication {

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

{% endcode %}

## 远程接口定义

在服务调用端，需要根据服务提供者的接口定义声明远程接口。其中`name`属性对应服务提供者在注册中心的serviceId，`path`属性对应`@RequestMapping`配置。

{% code title="FooClient.java" %}

```java
package com.example.demo.client;

import com.example.demo.dto.FooDto;
import feign.QueryMap;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "foo-service", path = "/foos")
public interface FooClient {

    @GetMapping("/{id}")
    FooDto findById(@PathVariable("id") Long fooId);

    @GetMapping("/all")
    List<FooDto> findAll(@RequestParam @QueryMap Map parameters);
}
```

{% endcode %}

对应的服务端代码：

{% code title="FooController.java" %}

```java
package com.example.demo.controller;

import com.example.demo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/foos")
public class FooController {

    @Autowired
    private FooService fooService;
    
    @GetMapping("/{id}")
    public FooDto findById(@PathVariable("id") Long id) {
        return fooService.findById(id);
    }
    
    @GetMapping("/all")
    public List<FooDto> findAll(FooQo fooQo) {
        return fooService.findAll(fooQo);
    }
}
```

{% endcode %}

{% hint style="info" %}
可以使用swagger-codegen插件，根据接口自动生成Feign Client。
{% endhint %}

{% hint style="info" %}
如果服务端方法定义的HTTP GET接口参数为封装的对象，在调用端需要使用`Map<String, Object>`作为参数，并且增加`@RequestParam`和`@QueryMap`注解，分别表示参数出现在HTTP请求行，并且为封装的内容。
{% endhint %}

## 远程服务调用

在业务逻辑层中，只需注入远程接口的实例，和本地方法一样进行调用即可。

{% code title="BarService.java" %}

```java
package com.example.demo.service;

import com.example.demo.client.FooClient;
import com.example.demo.dto.FooDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BarService {

    @Autowired
    private FooClient fooClient;

    public FooDto getFoo(Long fooId) {
        return fooClient.findById(fooId);
    }
}
```

{% endcode %}

## 参考文档

关于OpenFeign技术的更多内容请参考官方文档：<https://cloud.spring.io/spring-cloud-static/Finchley.SR1/multi/multi__spring_cloud_openfeign.html>
