声明式:接口声明、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方式调用的。
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=*
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 findAll();
}
依赖: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 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
创建PersonServiceController
@RestController
public class PersonServiceController implements PersonService{
private final ConcurrentHashMap map = new ConcurrentHashMap();
@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 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
调整person-client关闭Eureka
ribbon.eureka.enabled = false
person-service.ribbon.listOfServers = http://localhost:9090,http://localhost:9090,http://localhost:9090
将其注释掉 //@EnableEurekaClient
自定义Ribbon的规则
IRule
实现IRule
public class MyRule extends RandomRule{
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
@Override
public Server choose(Object key) {
ILoadBalancer balancer = getLoadBalancer();
List allServers = balancer.getAllServers();
//默认只返回第一个服务
return allServers.get(0);
}
}
@Bean
public MyRule myRule() {
return new MyRule();
}
@RibbonClient(value = "person-service",configuration = MyRule.class)
[localhost:9090, localhost:9090, localhost:9090]
@FeignClient(value = "person-service" ,fallback = PersonServiceFallBack.class)//服务方应用的名称
public interface PersonService {
@PostMapping("/person/save")
boolean save(@RequestBody Person person);
@GetMapping("/person/findall")
Collection findAll();
}
public class PersonServiceFallBack implements PersonService{
@Override
public boolean save(Person person) {
return false;
}
@Override
public Collection findAll() {
return Collections.emptyList();
}
}
@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();
}
}