Spring Cloud Combat Series (3) — Декларативные клиентские вызовы Feign

Spring Cloud

Связанный

  1. Spring Cloud Combat Series (1) — регистрация и обнаружение сервисов Eureka

  2. Spring Cloud Combat Series (2) — клиентский вызов + лента

  3. Spring Cloud Combat Series (3) — Декларативное притворство клиента

  4. Боевая серия Spring Cloud (4) - Fuse Hystrix

  5. Spring Cloud Combat Series (5) — Service Gateway Zuul

  6. Spring Cloud Combat Series (6) — Распределенный центр конфигурации Spring Cloud Config

  7. Spring Cloud Combat Series (7) — отслеживание служебных ссылок Spring Cloud Sleuth

  8. Spring Cloud Combat Series (8) — Мониторинг микросервисов Spring Boot Admin

  9. Spring Cloud Combat Series (9) — Аутентификация и авторизация службы Spring Cloud OAuth 2.0

  10. Практическая серия Spring Cloud (10) — Единый вход JWT и Spring Security OAuth

предисловие

В предыдущей статье я описал как пройтиRestTemplateСотрудничатьRibbonпотреблять услуги.FeignЯвляетсядекларативныйизHTTP поддельный клиент,поставкаориентированный на интерфейсизHTTP Звонок клиентапрограммирование. В этой статье далее объясняется, как пройтиFeignпотреблять услуги.

  • FeignПросто создайтеинтерфейси предоставитьаннотацияможно назвать.

  • FeignимеютПодключаемыйФункция аннотации , вы можете использоватьFeign аннотацияа такжеJAX-RS аннотация.

  • Feignслужба поддержкиПодключаемыйизКодера такжедекодер.

  • Feignинтегрировано по умолчаниюRibbon, можно комбинировать сEurekaИспользуется в комбинации, по умолчанию реализованоБалансировка нагрузкиЭффект.

текст

1. Создайте модуль контракта на обслуживание

Создаватьservice-contractпроектModule, после создания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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.ostenant.github.springcloud</groupId>
    <artifactId>service-contract</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>service-contract</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

        <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.ostenant.github.springcloud</groupId>
            <artifactId>service-contract</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

существуетservice-contractопределено вбизнес-интерфейси связанные с нимиDTOОбъекты следующие:

User.java

public class User implements Serializable {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void getName() {
        return this.name;
    }

    public String setName() {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

UserContract.java

UserContractОпределенныйUserВсякое поведение есть использование@FeignClientаннотированныйДекларативный интерфейс службы. в,@FeignClientизvalueуказанопоставщики услугизнаименование услуги.

@FeignClient("service-provider")
public interface UserContract {
    @PostMapping("/user")
    void add(@RequestBody User user);

    @GetMapping("/user/{name}")  
    User findByName(@PathVariable String name);

    @GetMapping("/users")
    List<User> findAll();
}

запоставщики услуг, необходимо реализоватьUserContractметоды интерфейса; дляпотребители услуг, его можно вводить напрямуюUserContractтак какклиентская заглушкаиспользовать.

2. Создайте поставщика услуг

Создаватьservice-providerпроектModule, импортируется после созданияМодуль сервисного контрактазависимость,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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.ostenant.github.springcloud</groupId>
    <artifactId>service-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>service-provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.ostenant.github.springcloud</groupId>
            <artifactId>service-contract</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>
        </dependencies>
    </dependencyManagement>

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

пройти черезаннотация @EnableEurekaClientпоказать себя одинEureka Client.

@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceProviderApplication.class, args);
    }
}

создать классUserService,выполнитьUserContractКонкретный бизнес интерфейса предоставляется извнеUserСвязанныйHTTPоказание услуг.

@RestController
public class UserService implements UserContract {
    private static final Set<User> userSet = new HashSet<>();

    static {
        userSet.add(new User("Alex", 28));
        userSet.add(new User("Lambert", 32));
        userSet.add(new User("Diouf", 30));
    }

    @Override
    public void add(@RequestBody User user) {
        userSet.add(user);
    }

    @Override
    public User findByName(@PathVariable String name) {
        return userSet.stream().filter(user -> {
            return user.getName().equals(name);
        }).findFirst();
    }

    @Override
    public List<User> findAll() {
        return new ArrayList<>(userSet);
    }
}

существуетконфигурационный файлотмечено вРеестр услугадрес,application.ymlФайл конфигурации выглядит следующим образом:

spring:
  active:
    profiles: sp1 # sp2

---

spring:
  profiles: sp1
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8770
spring:
  application:
    name: service-provider

---

spring:
  profiles: sp2
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8771
spring:
  application:
    name: service-provider

соответственно сspring.profiles.active=sp1а такжеspring.profiles.active=sp2так какSpring Bootизпараметры команды запуска,существуетНомер порта 8770а также8771запускать2индивидуальныйпоставщики услугпример.

3. Создайте потребителя услуги

создать новый проектModule, по имениservice-consumer, в егоpomимпортируется в файлFeignизЗависит от запускаа такжеМодуль сервисного контракта, код показан ниже:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.ostenant.github.springcloud</groupId>
    <artifactId>service-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>service-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.ostenant.github.springcloud</groupId>
            <artifactId>service-contract</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>
        </dependencies>
    </dependencyManagement>

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

конфигурационный файл в проектеapplication.ymlфайл, указанныйИмя приложениязаservice-consumer,Номер портаза8772,Адрес регистрации службызаhttp://localhost:8761/eureka/, код показан ниже:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8772
spring:
  application:
    name: service-feign

В стартовом классе приложенияServiceConsumerApplicationдобавить@EnableFeignClientsАннотация включенаFeignфункция.

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceConsumerApplication {

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

определитьUserControllerконтроллер для вызовапоставщики услугпредоставляемые услуги иоткликвнешний интерфейс.

@RestController
public class UserController {
    @Autowired
    private UserContract userContract;

    @PostMapping("/user")
    public void add(@RequestBody User user) {
        userContract.add(user);
    }

    @GetMapping("/user/{name}")
    public User findByName(@PathVariable String name) {
        return userContract.findByName(name);
    }

    @GetMapping("/users")
    public List<User> findAll() {
        return userContract.findAll();
    }
}

существуетслой управления UserControllerпредставлятьFeignинтерфейс, через@FeignClient(наименование услуги), чтобы указать, что вызываетсяСлужить.

запускатьпотребители услугприложение, доступhttp://localhost:8772/usersтестовое заданиепотребители услугполучить доступ к подключению, содержание ответа:

[
    {
      "name": "Alex",
      "age": 28
    },
    {
      "name": "Lambert",
      "age": 32
    },
    {
      "name": "Diouf",
      "age": 30
    }
]

4. Процесс реализации исходного кода Feign

В основном,Feignизреализация исходного кодаПроцесс выглядит следующим образом:

  1. сначала через@EnableFeignClientsАннотация включенаFeignClientфункция. только этоаннотациясуществует только при запуске программызапускать @FeignClient аннотацияизсканирование пакетов.

  2. поставщики услугреализация на основеFeignизконтрактный интерфейс, И вконтрактный интерфейсдобавить выше@FeignClientаннотация.

  3. потребители услугПосле запускасканирование пакетовоперация, сканировать все@FeignClientизаннотацияclass и внедрить эту информацию вSpringв контексте.

  4. когдаинтерфейсметод вызываетсяJDKизиграет рольдля создания конкретныхRequestTemplate объект шаблона.

  5. согласно сRequestTemplateрегенерацияHTTPпросилRequestобъект.

  6. RequestВозражатьClientобрабатывать, чтоClientв линиюПлатформа веб-запросоввозможноHTTPURLConnection,HttpClientа такжеOkHttp.

  7. наконецClientзаключен вLoadBalanceClientкласс, этот класс объединяетRibbonЗаканчиватьБалансировка нагрузкиФункция.

Ссылаться на

  • Фан Чжипэн «Глубокое понимание Spring Cloud и построения микросервисов»

Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack

零壹技术栈

Эта учетная запись будет продолжать делиться сухими товарами серверных технологий, включая основы виртуальных машин, многопоточное программирование, высокопроизводительные фреймворки, асинхронное ПО, промежуточное ПО для кэширования и обмена сообщениями, распределенные и микросервисы, материалы для обучения архитектуре и расширенные учебные материалы и статьи.