# 服务调用

需要进行模块之间的服务调用时，使用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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://taocares.gitbook.io/development-guide/kai-fa-zhi-nan/fu-wu-tiao-yong.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
