Spring Cloud 聲明式服務調用 Feign

1、簡介java

 在上一篇中,咱們介紹註冊中心Eureka,可是沒有服務註冊和服務調用,服務註冊和服務調用原本應該在上一章就應該給出例子的,可是我以爲仍是和Feign一塊兒講比較好,由於在實際項目中,都是使用聲明式調用服務。而不會在客服端和服務端存儲2份相同的model和api定義。Feign在RestTemplate的基礎上對其封裝,由它來幫助咱們定義和實現依賴服務接口的定義。Spring Cloud Feign 基於Netflix Feign 實現的,整理Spring Cloud Ribbon 與 Spring Cloud Hystrix,而且實現了聲明式的Web服務客戶端定義方式。web

2、實踐spring

在上一節中,我繼續添加工程模塊,最後的模塊以下:apache

首先咱們須要建一個工程,名爲hello-service-api 在工程主要定義對外提供的model 和api。服務的提供方和服務的消費方都要依賴該工程jar,這樣咱們就能夠只維護一份model 和api定義。在該例子中主要以下結構json

 

很是簡單,只有1個HelloServieRemoteApi 接口定義和User對象。api

@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爲主。app

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以下:maven

<?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,依賴越少越好。ide

接下來咱們須要建立一個提供者工程,咱們把它命名爲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.

相關文章
相關標籤/搜索