Feign

1. Feign 和 OpenFeign

Feign

Feign是Springcloud组件中的一个轻量级Restful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务

依赖包:

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

OpenFeign

OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
依赖包:

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

2. 利用OpenFeign调用远程服务 

OpenFeign是在基于客户端的。

2.1 依赖包

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

2.2 启动类

需要加@EnableFeignClients 注解

2.3 服务调用

1. 创建一个接口,接口加@FeignClient配置。该接口不需要实现

2. 将接口注入到FeignController,让后调用接口方法。

一般来说,我们直接注入接口是不行的,会报错。但是这里不会报错,一定记得在启动类加上@EnableFeignClients注解,该该注解就不会报错了

3. 那这是如果调用的呢,原理是什么。

Feign相当于是对RestTemplate进行的封装,RestTemplate调用是需要知道一个url的,且需要用RestTemplate的一些方法进行调用。

而OpenFeign这是利用注解进行调用,以下面例子为例:

当调用appInter.gethelloOne()方法时,Feign在这里检测到调用,把这个调用拦截住,利用@FeignClient注解,将provider和方法的RequestMapping的路径组成一个请求路径,http://provider/helloOne,然后Feign去调用远程服务,当远程服务进行返回时,feign把响应拦截处理,最终返回给appInter.gethelloOne()调用的返回。

Feign的操作本质上就是通过动态代理的方式,生成一个代理类,在代理类中进行了一系列的操作,肯定有RestTemplate调用远程服务,Ribbon的负载均衡。

服务调用方

@FeignClient(name = "provider")
public interface AppInter {

    @RequestMapping("/helloOne")
    public String getHelloOne();

}

 

@RestController
public class FeignController {

    @Autowired
    AppInter appInter;

    @RequestMapping("/helloOne")
    public String HelloOne(){
        return appInter.getHelloOne();
    }

}

服务提供方

@RestController
public class HelloController {

    @Value("${server.port}")
    private String port;

    @RequestMapping("/helloOne")
    public String getHelloOne(){

        return port+":"+"helloOne";
    }

}

2.4 Get和Post

Feign所有带参数的请求,默认都是Post请求,如果想要使用指定的方式,需要引入依赖httpClient。。目前发现不配置也行

 

2.5 引入API

1. 创建一个新boot项目。创建一个API,相当于消费者和服务提供者直接的接口

package com.tzw.user;

import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/user")
public interface UserApi {

    @RequestMapping("/alive")
    public String alive();
}

2. 将此项目打包,

mvn install 

3. 将此项目依赖到客户端和服务端

        <dependency>
            <groupId>com.tzw</groupId>
            <artifactId>user-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

 

4. 客户端代码,extends UserApi,客户端继承API

package com.example.consumer;

import com.tzw.user.UserApi;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "provider")
public interface AppInter extends UserApi {

    @RequestMapping("/helloOne")
    public String getHelloOne();

    @RequestMapping(value="/helloTwo")
    public String getHelloTwo(@RequestParam String name);

    @RequestMapping(value="/helloThree")
    public String getHelloThree(@RequestBody String name);

    @RequestMapping("/user")
    public String getUserbyId(@RequestParam String id);
}

5. 服务提供端代码,implement UserAPI,服务提供端实现该API。

package com.example.provider;

import com.tzw.user.UserApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
public class HelloController implements UserApi {

    @Value("${server.port}")
    private String port;

    @RequestMapping("/helloOne")
    public String getHelloOne(){

        return port+":"+"helloOne";
    }

    @GetMapping("/helloTwo")
    public String getHelloTwo(@RequestParam  String name){

        return port+":"+name;
    }

    @PostMapping("/helloThree")
    public String getHelloThree(@RequestBody  String name){

        return port+":"+name;
    }


    @Override
    public String alive() {
        return "I'm alive";
    }

    @RequestMapping("/user")
    public String getUserbyId(@RequestParam String id){
        return "用户名称:张三-----"+"用户id:"+id;

    }
}

6. 总结

API相当于两个系统间的接口,一般有服务提供者设计,开发时可以直接维护该API。注意打包时的问题,boot-inf mata-inf,解决办法

API中可以用@RequestMapping注释,用来在Feign调用是拼接URl。也就是说,以上的例子,feign在调用alive是,url应该是http://localhost:9999/user/alive。而不是http://localhost:9999/alive

这也是OpenFeign的特性,OpenFeign可以解析@RequestMapping这些注解,并进行url拼接。

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

服务消费者继承该API,可以直接进行调用。

服务提供这实现该API,以供服务消费调用。实现方法可以不在加@RequestMapping等注释,在接口中加注释,实现类可以不用加。

2.6 Feign日志

配置日志的两种方式,

通过配置文件配置

#配置日志
feign.client.config.provider.logger-level=full

#上面的logger-level只对下面的 debug级别日志做出响应。
# feign日志已什么级别监控哪个接口
logging.level.com.example.consumer.AppInter=debug

feign.client.config.provider.logger-level=full        

注:provider是调用的远程服务名称
//上面有4种日志类型
none:不记录任何日志,默认值
basic:仅记录请求方法,url,响应状态码,执行时间。
headers:在basic基础上,记录header信息
full:记录请求和响应的header,body,元数据。
        

# feign日志已什么级别监控哪个接口
logging.level.com.example.consumer.AppInter=debug
logging.level.com.example.consumer.*=debug 可以用* 指代所以接口。

二通过配置类配置

 /**
     * 开启日志等级
     * @return
     */
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.FULL;
    }

 

2.7超时

Feign默认支持Ribbon;Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制.

配置超时时间,

连接超时,在获取连接的时候的超时。一般是网络导致的。

业务逻辑超时,一般是业务逻辑过程中的超时。

#连接超时时间(ms)
ribbon.ConnectTimeout=1000
#业务逻辑超时时间(ms)
ribbon.ReadTimeout=6000

2.8 重试

有超时就有重试。

#同一台实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetries=1
#重试负载均衡其他的实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetriesNextServer=1
#是否所有操作都重试
ribbon.OkToRetryOnAllOperations=false

使用ribbon重试机制,请求失败后,每个6秒会重新尝试

HyStrix

这个重试机制不太友好,就引出了Hystrix机制

spring cloud 用的是 hystrix,是一个容错组件。

Hystrix实现了 超时机制和断路器模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值