微服务架构spring cloud - 声明式服务调用 Feign(五)

1.什么是Feign 

总的来说就是ribbion和hystrix的结合体,由于使用restTemplate的麻烦和重复性,所以有了这一个组件包装了ribbion和hystrix,不过需要注意的是底层还是使用ribbion和hystrix,只是使用注解的方式优雅的实现了这个负载均衡和断路器。

2.快速人们

1.配置依赖

<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-feign</artifactId>
        </dependency>

2.加入注解

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class FeignConsumerApplication {

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

3.设计消费服务,创建service

@FeignClient里面填写的是需要消费的服务名称

@RequestMapping 这里是feign对springmvc的扩展支持

@RequestParam 必须加value

@RequestHead 必须加value

@RequestBody 不用必须加value


@FeignClient("hello-service")
public interface HelloService {

    @RequestMapping("/hello")
    String hello();

    @RequestMapping("hello1")
    public String index1(@RequestParam(value = "name") String name);

    @RequestMapping("hello2")
    public User index2(@RequestHeader(value = "name") String name);

    @RequestMapping("hello3")
    public String index3(@RequestBody User user);

}

4.控制器

@RestController
public class ConsumerController {

    @Autowired
    HelloService helloService;

    @RequestMapping(value = "/feign-consumer",method = RequestMethod.GET)
    public String helloConsumer() {
        return helloService.hello();
    }


    @RequestMapping(value = "/feign-consumer2",method = RequestMethod.GET)
    public String helloConsumer2() {
        StringBuilder stringBuilder=new StringBuilder();
        User user=new User();
        user.setName("llx");
        stringBuilder.append(helloService.index1("llg")).append("\n");
        stringBuilder.append(helloService.index2("llg")).append("\n");
        stringBuilder.append(helloService.index3(user)).append("\n");
        return stringBuilder.toString();
    }


}

5.配置属性

扫描二维码关注公众号,回复: 2688663 查看本文章
spring.application.name=feign-consumer
server.port=9001
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

3.继承特性

为了解决类似于接口与controller重复问题,将统一资源抽象成接口,服务提供者根据此接口提供服务,服务消费者通过此接口和feign直接绑定服务。

好处:不用再重复的写接口的定义

坏处:麻烦,由于依赖maven私有仓库,当接口变动的时候需要改变多出地方

1.首先创建一个新的maven项目,构建接口


@RequestMapping("/refactor")
public interface HelloService {


    @RequestMapping("hello4")
    public String index1(@RequestParam(value = "name") String name);

    @RequestMapping("hello5")
    public User index2(@RequestHeader(value = "name") String name);

    @RequestMapping("hello6")
    public String index3(@RequestBody User user);

}

2.根据依赖的接口对象写服务提供者的Controller对象,在这里通过重写方法可以将注解也继承下来,所以无需再加注解,记得加Controller注解即可

@RestController
public class RefactorHelloController implements HelloService {
    @Override
    public String index1(@RequestParam String name){

        return name;
    }

    @Override
    public User index2(@RequestHeader String name){
        User user=new User();
        user.setName(name);
        return user;
    }

    @Override
    public String index3(@RequestBody User user){

        return "User3 : "+user.getName();
    }
}

3.服务消费者根据接口只需要继承即可


@FeignClient(value="hello-service")
public interface RefactorHelloService extends HelloService {
}

4.服务消费者通过service进行消费


@RestController
public class ConsumerController {

    @Autowired
    RefactorHelloService refactorHelloService;
    
    @RequestMapping(value = "/feign-consumer3",method = RequestMethod.GET)
    public String helloConsumer3() {
        StringBuilder stringBuilder=new StringBuilder();
        User user=new User();
        user.setName("llx");
        stringBuilder.append(refactorHelloService.index1("llg")).append("\n");
        stringBuilder.append(refactorHelloService.index2("llg")).append("\n");
        //stringBuilder.append(refactorHelloService.index3(user)).append("\n");
        return stringBuilder.toString();
    }

}

4.Ribbon配置

启动了Feign的时候同时也会启动Ribbion,也就是说@FeignClient(value="hello-servuce")不仅启动了一个名字叫hello-service的客户端,还启动了一个同名的Ribbion客户端

所以只需要在配置文件上配置负载均衡信息即可,切记如果需要配置全局信息只要把代表client信息的hello-servce删除即可

hello-service.ribbion.ConnectTimeout=250 请求连接超时间

hello-service.ribbion.ReadTimeout=1000 请求处理超时时间

heelo-service.ribbion.OkToRetryAllOperations=true 对所有请求都进行重试

heelo-service.ribbion.MaxAutoRetriesNextServer=2  切换实例的重试次数

hello-service.ribbion.MaxAutoRetries=1 对当前实例的重试次数

注意:ribbion的超时与hystrix的超时是不一样的,ribbion的超时说的是重试时候的超时,可以重试调用同一个实例,不然就会调用另外一个实例,所以需要知道的是必须让Hystrix的超时时间大于Ribbion的超时时间,否则断路器打开就不好了。

5.Hystrix配置

使用Feign之后,自动帮我们将所有方法都封装到了Hystrix命令中

全局配置:直接使用默认前缀hystrix.command.default

例如:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

注意:需要Hystrix服务的时候,要确保feign.hystrix.enabled=true有没有打开

禁用Hystrix

全局禁用:feign.hystrix.enabled=false

局部禁用:用过配置类,禁用某个服务客户端


@Configuration
public class DisableHystrixConfiguration {

    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilfer(){
        return Feign.builder();
    }
}
@FeignClient(value = "hello-service",configuration = DisableHystrixConfiguration.class)
public interface HelloServicess {

    @RequestMapping("/hello")
    String hello();

    @RequestMapping("hello1")
    public String index1(@RequestParam(value = "name") String name);

    @RequestMapping("hello2")
    public String index2(@RequestHeader(value = "name") String name);

    @RequestMapping("hello3")
    public String index3(@RequestBody User user);

}

指令命令配置

采用hystrix.commond.<commonKey>作为前缀,而在Feign中则是把方法名设置为commonkey命令名

例如hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=500

注意:由于使用方法名有重复的风险,所以要么在方法名上尽量不重复,要么在Feign.build上重写

public static String configKey(Class targetType, Method method) {
        StringBuilder builder = new StringBuilder();
        builder.append(targetType.getSimpleName());
        builder.append('#').append(method.getName()).append('(');
        Type[] var3 = method.getGenericParameterTypes();
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Type param = var3[var5];
            param = Types.resolve(targetType, targetType, param);
            builder.append(Types.getRawType(param).getSimpleName()).append(',');
        }

        if (method.getParameterTypes().length > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }

        return builder.append(')').toString();
    }

服务降级配置

相比较于之前的ribbion的配置,使用Feign写服务降级逻辑则有点不一样,首先实现service接口的实现类,然后将此实现类写入@FeignClient的注解属性fallbcak中

@FeignClient(value = "hello-service",configuration = DisableHystrixConfiguration.class)
public interface HelloServicess {

    @RequestMapping("/hello")
    String hello();

    @RequestMapping("hello1")
    public String index1(@RequestParam(value = "name") String name);

    @RequestMapping("hello2")
    public String index2(@RequestHeader(value = "name") String name);

    @RequestMapping("hello3")
    public String index3(@RequestBody User user);

}
public class HelloServiceFallback implements HelloService {
    @Override
    public String index1(String name) {
        return "error";
    }

    @Override
    public User index2(String name) {
        return new User();
    }

    @Override
    public String index3(User user) {
        return "error3";
    }
}
@FeignClient(value="hello-service",fallback = HelloServiceFallback.class)
public interface RefactorHelloService extends HelloService {
}

6.其他配置

请求压缩

指的是将请求内容和响应内容通过gzip压缩,降低性能损耗

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 只有超过此大小的请求才会被压缩(默认值)

7.日志配置

每一个@FeignClient客户端都自动创建了feign.Logger实例

通过配置可以开启

logging.level.<FeignClient>.xxxx

例如:logging.level.com.llg.demo.HelloService=DEBUG

紧接着还必须继续配置Bean


@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class FeignConsumerApplication {
    
    @Bean
    Logger.Level feingnLoggerLevel(){
        return Logger.Level.FULL;
    }

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

还可以通过刚刚使用配置类来局部禁用Hystrix的配置类来配置Bean,可以达到局部配置日志级别的目的。

    @Configuration
    public class DisableHystrixConfiguration {

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

        @Bean
        @Scope("prototype")
        public Feign.Builder feignBuilfer(){
            return Feign.builder();
        }
    }
@FeignClient(value = "hello-service",configuration = DisableHystrixConfiguration.class)
public interface HelloServicess {

    @RequestMapping("/hello")
    String hello();

    @RequestMapping("hello1")
    public String index1(@RequestParam(value = "name") String name);

    @RequestMapping("hello2")
    public String index2(@RequestHeader(value = "name") String name);

    @RequestMapping("hello3")
    public String index3(@RequestBody User user);

}

总结:对于Feign级别有4种

NONE:不记录任何信息

BASIC:仅记录请求方法,URL,响应状态码和执行时间

HEADERS:包括basic还有记录请求和响应的头信息

FULL:记录所有请求数据

猜你喜欢

转载自blog.csdn.net/m0_37834471/article/details/81463233