Spring Cloud 声明式服务调用 Feign

一、简介

在上一篇中,我们介绍注册中心Eureka,但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和Feign一起讲比较好,因为在实际项目中,都是使用声明式调用服务。而不会在客服端和服务端存储2份相同的model和api定义。Feign在RestTemplate的基础上对其封装,由它来帮助我们定义和实现依赖服务接口的定义。Spring Cloud Feign 基于Netflix Feign 实现的,整理Spring Cloud Ribbon 与 Spring Cloud Hystrix,并且实现了声明式的Web服务客户端定义方式。

二、实践

在上一节中,我继续添加工程模块,最后的模块如下:

首先我们需要建一个工程,名为hello-service-api 在工程主要定义对外提供的model 和api。服务的提供方和服务的消费方都要依赖该工程jar,这样我们就可以只维护一份model 和api定义。在该例子中主要如下结构

非常简单,只有1个HelloServieRemoteApi 接口定义和User对象。

@RequestMapping("/hello-service-remote")
public interface HelloServiceRemoteApi {

    @RequestMapping(value = "/hello1", method = RequestMethod.GET)
    String hello(@RequestParam("name") String name);

    @RequestMapping(value = "/hello2", method = RequestMethod.GET)
    User hello(@RequestHeader("name") String name,@RequestHeader("age") Integer age);

    @RequestMapping(value = "/hello3", method = RequestMethod.POST)
    String hello(@RequestBody User user);

}

在上面的接口定义中,我们非常的清晰,在接口上面我们主映射为/hello-service-remote,个人感觉已接口的名字通过“-”这样可以非常的区分不同的接口路径,防止多接口时发生重复。接下来具体方法的上面可以定义于方法名一样的路径映射,我这里已 /hello1,/hello2,/hello3为主。

public class User implements Serializable {
    private static final long serialVersionUID = -7233238826463139634L;

    private Long id;

    private String name;

    private Integer age;

    public User() {
    }

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

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name=‘" + name + ‘\‘‘ +
                ", age=" + age +
                ‘}‘;
    }
}

上面就是简单的一个User对象。 

从上面的接口中发现,该api工程需要引入spring-web包。所以它的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>

    <artifactId>hello-service-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <groupId>com.qee.hello</groupId>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.9.RELEASE</version>
        </dependency>
    </dependencies>
</project>

  从上面的pom.xml定义中,我们知道hello-service-api并不集成父工程micro-service-integration。一般作为api提供的工程jar,依赖越少越好。

接下来我们需要创建一个提供者工程,我们把它命名为hello-service-compose。该工程也是标准的Spring Boot工程。具体的目录如下:

  在工程中我们有一个刚才hello-service-api接口定义的实现。代码如下:

@RestController
public class HelloServiceRemoteApiImpl implements HelloServiceRemoteApi {

    @Override
    public String hello(@RequestParam("name") String name) {
        return "hello " + name;
    }

    @Override
    public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
        try {
            name= URLDecoder.decode(name,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new User(name, age);
    }

    @Override
    public String hello(@RequestBody User user) {
        if (user == null) {
            return "未知";
        }
        return user.toString();
    }
}

因为是测试工程,所以它没有复杂的业务逻辑。接下来就是HelloProviderApplication的启动main.

package com.qee.remote;

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

@EnableDiscoveryClient
@SpringBootApplication
public class HelloProviderApplication {

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

在上面有2个注解,第一个 SpringBootApplication 就是Spring Boot 启动注解,EnableDiscoveryClient 该注解会把RestController修饰的类注册到注册中心去。

接下来我们来看下application.properties

server.port=8885

spring.application.name=hello-service-compose

eureka.instance.hostname=register.center.com

eureka.instance.server.port=8881

#默认的注册域
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/

#控制台彩色输出
spring.output.ansi.enabled=ALWAYS

从上面信息我们知道,改工程启动端口为8885,注册中心地址为register.center.com:8881。

接下来我们查看一下该工程的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">
    <parent>
        <artifactId>micro-service-integration</artifactId>
        <groupId>spring.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hello-service-compose</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.qee.hello</groupId>
            <artifactId>hello-service-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

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

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

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

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

    </dependencies>
</project>

  从pom.xml文件中知道该工程依赖了web,euraka,ribbon,actuator,hello-service-api 包。其中euraka为服务注册和发现包,ribbon为服务调用负载均衡包,actuator为工程元信息检测包。还有我们自己定义的hello-service-api包。

在上面的简单配置和编写后,我们就可以启动工程把该HelloServiceRemoteApi注册到注册中心去了。

  现在有了服务接口定义包和服务提供工程,现在我们编写一下服务调用工程。命名为hello-service-web。该工程的目录结构如下:

首先我们来看下HelloBackgroundService 这个接口。

@FeignClient(value = "hello-service-compose")
public interface HelloBackgroundService extends HelloServiceRemoteApi{
}

 非常的简单,主要继承我们之前编辑的HelloServiceRemoteApi,并且在上面打上FeignClient注解,该注解指定服务名来绑定服务。该注解同时会使服务调用具有负载均衡的能力。

接下来我们来看下HelloController类

@RestController
public class HelloController {

    @Autowired
    private HelloBackgroundService helloBackgroundService;

    @RequestMapping("/hello")
    public Map<String,Object> hello(){
        Map<String,Object> ret = new HashMap<String, Object>();
        StringBuffer sb = new StringBuffer();
        String s1 = helloBackgroundService.hello("张三");
        sb.append(s1).append("\n");
        User user = null;
        try {
            user = helloBackgroundService.hello(URLEncoder.encode("李四", "UTF-8"), 30);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        sb.append(user.toString()).append("\n");
        String s3 = helloBackgroundService.hello(new User("王五", 19));
        sb.append(s3).append("\n");
        ret.put("show",sb.toString());
        return ret;
    }
}

  从上面得知我们,我们就可以调用之前的我们编写的HelloBackgroundService了。接下来我们查看一下启动类HelloConsumerApp

  

package com.qee;

import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class HelloConsumerApp {

    @Bean
    Logger.Level feginLoggerLevel(){
        return Logger.Level.FULL;
    }

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

 在该启动了中又多了一个注解EnableFeignClients ,该注解开启Spring Cloud Feign的支持。接着我们来查看一下application.properties

server.port=8887

spring.application.name=hello-service-web

eureka.instance.hostname=register.center.com

eureka.instance.server.port=8881

#默认的注册域
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/

#开启请求压缩功能
feign.compression.request.enabled=true

#开启响应压缩功能
feign.compression.response.enabled=true

#指定压缩请求数据类型
feign.compression.request.mime-types=text/xml;application/xml;application/json

#如果传输超过该字节,就对其进行压缩
feign.compression.request.min-request-size=2048

#控制台彩色输出
spring.output.ansi.enabled=ALWAYS

#日志配置,该接口的日志级别
logging.level.com.qee.service.HelloBackgroundService=DEBUG

 从上面的注释中,我们已经可以知道具体的配置参数的作用,这里就不详细介绍了。从上面的配置和编写我们可以知道,该工程需要如下的依赖包,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">
    <parent>
        <artifactId>micro-service-integration</artifactId>
        <groupId>spring.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hello-service-web</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.qee.hello</groupId>
            <artifactId>hello-service-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

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

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</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-actuator</artifactId>
        </dependency>

    </dependencies>
</project>

  该服务消费端,比服务提供方多了一个jar依赖,就是feign。该jar的作用就是提供声明式的服务调用。到这里我们本章的内容大致结束,最后我们来运行这几个工程。查看如下结果:

从上面我们可以看到2个工程hello-service-compose 和hello-service-web都已经注册到注册中心eureka上了。接下来看一下调用结果:

到这里服务注册中心启动,服务注册,服务消费大致都已完成,之后会向大家一起学习服务调用的负载均衡Ribbon和服务容错保护Hystrix.

 

时间: 2024-10-11 19:13:15

Spring Cloud 声明式服务调用 Feign的相关文章

005声明式服务调用Feign

1.POM配置 和普通Spring Boot工程相比,添加了Eureka Client.Feign.Hystrix.Spring Boot Starter Actuator依赖和Spring Cloud依赖管理 <dependencies> <!--Eureka Client依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>sprin

Spring Cloud第七篇 | 声明式服务调用Feign

本文是Spring Cloud专栏的第七篇文章,了解前六篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cloud第二篇 | 使用并认识Eureka注册中心 Spring Cloud第三篇 | 搭建高可用Eureka注册中心 Spring Cloud第四篇 | 客户端负载均衡Ribbon Spring Cloud第五篇 | 服务熔断Hystrix Spring Cloud第六篇 | Hystrix仪表盘监控Hy

【第三章】声明式服务调用(Feign)

当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻.那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign. Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单.Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数.格

干货分享微服务spring-cloud(5.声明式服务调用feign)

Spring cloud feign基于Netflix feign实现,整合了spring cloud ribbon与spring cloud hystrix,除了提供这两者的强大功能之外,它还提供了一种声明式的web服务客户端定义方式 新建spring boot工程并命名为demo-springcloud-feign-consumer,新建启动类FeignApplication,通过@ EnableFeignClients注解来开启spring cloud feign的功能支持 定义YhqSe

Spring Cloud Eureka 分布式开发之服务注册中心、负载均衡、声明式服务调用实现

介绍 本示例主要介绍 Spring Cloud 系列中的 Eureka,使你能快速上手负载均衡.声明式服务.服务注册中心等 Eureka Server Eureka 是 Netflix 的子模块,它是一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移. 服务注册和发现对于微服务架构而言,是非常重要的.有了服务发现和注册,只需要使用服务的标识符就可以访问到服务,而不需要修改服务调用的配置文件.该功能类似于 Dubbo 的注册中心,比如 Zookeeper. Eureka

申明式服务调用Feign之一:入门示例

新建一个spring-boot工程,取名为feign-consumer,在它的pom文件引入Feign的起步依赖spring-cloud-starter-feign.Eureka的起步依赖spring-cloud-starter-eureka.Web的起步依赖spring-boot-starter-web,pom代码如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w

SpringCloud无废话入门03:Feign声明式服务调用

1.Feign概述 在上一篇的HelloService这个类中,我们有这样一行代码: return restTemplate.getForObject("http://hello-service/hello",String.class); 对于代码有一定洁癖的你来说,一定感觉到了,这个url应该是可以被配置的.既然说到配置,那我们首先想到的就是使用java注解的方式.Feign就是这样一个注解框架,它也是netflix为我们提供的,方便我们整合ribbon和hystrix(后面会学习)

基于Spring Cloud的微服务落地

请点击此处输入图片描述 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud.它包括: Spring Cloud Config:配置管理工具,支持使用Git存储配置内容,可以实现应用配置的外部化存储,支持客户端配置信息刷新.加密/解密配置内容等. Spring Clo

写给新手的Spring Cloud的微服务入门教程

1. 微服务简介 1.1 什么是微服务架构 微服务架构是系统架构上的一种设计风格 将大系统拆分成N个小型服务 这些小型服务都在各自的线程中运行 小服务间通过HTTP协议进行通信 有自己的数据存储.业务开发.自动化测试和独立部署机制 可以由不同语言编写 小结:微服务架构的思想,不只是停留在开发阶段,它贯穿了设计,研发,测试,发布,运维等各个软件生命周期. 2. 架构体系 架构样例: 2.1 微服务发布--持续集成 3. 微服务架构九大特性 服务组件化-- 组件是可独立更换.升级的单元.就像PC中的