Spring Cloud - 6 (Spring Cloud Feign)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ysl19910806/article/details/97044989

声明式Web服务客户端:Feign


声明式:接口声明、Annotation驱动

Web服务:HTTP的方式作为通讯协议

客户端:用于服务调用的存根

Feign:原生并不是Spring Web MVC的实现,基于JAX-RS(Java REST 规范)实现。Spring Cloud封装了Feign,使其支持Spring Web MVC。RestTemplate、HttpMessageConverter

RestTemplate以及Spring Web MVC可以显式地自定义HTTPMessageConverter实现。

假设,有一个Java接口PersonService,Feign可以将其声明它是一种HTTP方式调用的。

注册中心(Eureka Server):服务发现和注册


应用名称:spring-cloud-eureka-server

application.properties:
spring.application.name=eureka-server
server.port=12345
##\u53D6\u6D88\u670D\u52A1\u5668\u81EA\u6211\u6CE8\u518C
eureka.client.register-with-eureka=false
##\u4E0D\u9700\u8981\u68C0\u7D22\u670D\u52A1
eureka.client.fetch-registry=false
management.endpoints.web.exposure.include=*

Feign声明接口(契约):定义一种Java强类型接口


模块:person-api

Person

public class Person {
    
    private Long id ;
    
    private String name;

    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;
    }
    
}

PersonService

@FeignClient(value = "person-service")//服务方应用的名称
public interface PersonService {
    
    @PostMapping("/person/save")
    boolean save(@RequestBody Person person);
    
    @GetMapping("/person/findall")
    Collection<Person> findAll();

}

Feign客户(服务消费)端:调用Feign声明接口


应用名称:person-client

依赖:person-api

创建客户端Controller

@RestController
public class PersonServiceController implements PersonService{

    private final PersonService personService;
    
    @Autowired
    public PersonServiceController(PersonService personService) {
        this.personService = personService;
    }
    
    @PostMapping("/person/save")//实现了PersonService接口后可以不用写mapping地址
    @Override
    public boolean save(@RequestBody Person person) {
        return personService.save(person);
    }

    @GetMapping("/person/findall")
    @Override
    public Collection<Person> findAll() {
        return personService.findAll();
    }
    
}

创建启动类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(clients = PersonService.class)
public class FeignClientBootStrapApplication {

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

}

配置application.properties

spring.application.name=person-client

server.port=8080

management.endpoints.web.exposure.include=*

eureka.client.serviceUrl.defaultZone=http://localhost:12345/eureka

Feign服务(服务提供)端:不一定强制实现Feign声明接口


应用名称:person-service

依赖:person-api

创建PersonServiceController

@RestController
public class PersonServiceController implements PersonService{

    private final ConcurrentHashMap<Long,Person> map = new ConcurrentHashMap<Long, Person>();
    
    @PostMapping("/person/save")//实现了PersonService接口后可以不用写mapping地址
    @Override
    public boolean save(@RequestBody Person person) {
        return map.put(person.getId(), person) == null;
    }

    @GetMapping("/person/findall")
    @Override
    public Collection<Person> findAll() {
        return map.values();
    }

}

创建服务端启动类

@SpringBootApplication
@EnableEurekaClient
public class FeignServiceBootStrapApplication {

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

}

配置application.properties

spring.application.name=person-service

server.port=9090

management.endpoints.web.exposure.include=*

eureka.client.serviceUrl.defaultZone=http://localhost:12345/eureka

Feign客户(服务消费)端、Feign服务(服务提供)端,以及Feign声明接口(契约)存放在同一个工程目录。

调用顺序


浏览器 ->person-client->person-service

person-api定义了@FeignClients(value="person-service"),person-service实际是一个服务器提供方的应用名称。 

person-client 可以感知person-service应用存在的,并且Spring Cloud帮助解析PersonService中声明的应用名称:

“person-service”,因此person-client在调用PersonService服务时,实际就路由到person-service的URL

整合Netflix Ribbon


关闭Eureka注册

调整person-client关闭Eureka

ribbon.eureka.enabled = false

定义服务ribbon的服务列表(服务名称:person-service)

person-service.ribbon.listOfServers = http://localhost:9090,http://localhost:9090,http://localhost:9090

完全取消Eureka注册

将其注释掉 //@EnableEurekaClient

自定义Ribbon的规则

接口和Netfilx内部实现

IRule

  • 随机规则:RandomRule
  • 最可用规则:BestAvailableRule
  • 轮询规则:RoundRobinRule
  • 重试实现:RetryRule
  • 客户端配置:ClientConfigEnableRoundRobinRule
  • 可用性过滤规则:AvailabilityFilteringRule
  • RT权重规则:WeightedResponseTimeRule
  • 规避区域规则:ZoneAvoidanceRule
     

实现IRule

public class MyRule extends RandomRule{
    
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }

    @Override
    public Server choose(Object key) {
        ILoadBalancer balancer = getLoadBalancer();
        
        List<Server> allServers = balancer.getAllServers();
        //默认只返回第一个服务
        return allServers.get(0);
    }
}

暴露自定义实现为Spring Bean

    @Bean
    public MyRule myRule() {
        return new MyRule();
    }

激活配置

@RibbonClient(value = "person-service",configuration = MyRule.class)

验证结果

[localhost:9090, localhost:9090, localhost:9090]

整合Netflix Hystrix


调整Feign接口

@FeignClient(value = "person-service" ,fallback = PersonServiceFallBack.class)//服务方应用的名称
public interface PersonService {
    
    @PostMapping("/person/save")
    boolean save(@RequestBody Person person);
    
    @GetMapping("/person/findall")
    Collection<Person> findAll();

}

添加Fallback实现

public class PersonServiceFallBack implements PersonService{

    @Override
    public boolean save(Person person) {
        return false;
    }

    @Override
    public Collection<Person> findAll() {
        return Collections.emptyList();
    }

}

调整客户端激活Hystrix

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(clients = PersonService.class)
@RibbonClient(value = "person-service",configuration = MyRule.class)
@EnableHystrix
public class FeignClientBootStrapApplication {

    public static void main(String[] args) {
        SpringApplication.run(FeignClientBootStrapApplication.class, args);
    }
    
    @Bean
    public MyRule myRule() {
        return new MyRule();
    }

}

猜你喜欢

转载自blog.csdn.net/ysl19910806/article/details/97044989