本文次要介绍SpringCloud中三种服务调用形式:

  • Spring DiscoveryClient
  • 反对Ribbon的RestTemplate
  • Feign客户端

搭建服务测试环境

测试中,服务发现层采纳Netflix的Eureka搭建。

次要步骤如下:

1.引入Eureka所需依赖

<!--eureka服务端-->  <dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-eureka-server</artifactId>  </dependency><!--客户端--><dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-eureka</artifactId></dependency>

2.批改配置文件

服务端:

eureka: instance:  hostname: eureka9001.com #eureka服务端的实例名称  instance-id: eureka9001client:  register-with-eureka: false #false示意不向注册核心注册本人  fetch-registry: false # #false 示意本人就是注册核心,职责就是保护服务实例,并不需要去检索服务  service-url:  defaulteZone: http://127.0.0.1:9001

客户端1:

server:  port: 8002spring:  application:    name: licensingserviceeureka:  instance:    instance-id: licensing-service-8002    prefer-ip-address: true  client:    register-with-eureka: true    fetch-registry: true    service-url:      defaultZone: http://127.0.0.1:9001/eureka/,

客户端2:

server: port: 8002spring: application:   name: licensingserviceeureka: instance:   instance-id: licensing-service-8002   prefer-ip-address: true client:   register-with-eureka: true   fetch-registry: true   service-url:     defaultZone: http://127.0.0.1:9001/eureka/,    

一组微服务的不同实例采服务名雷同,不同的实例Id辨别,别离对应,spring.application.nameeureka.instance.instance-id

3.启动服务

服务端:

@SpringBootApplication@EnableEurekaServerpublic class EurekaServerPort9001_App {  public static void main(String[] args) {    SpringApplication.run(EurekaServerPort9001_App.class,args);  }}

客户端:

@SpringBootApplication@RefreshScope@EnableEurekaClientpublic class LicenseApplication_8002 {    public static void main(String[] args) {        SpringApplication.run(LicenseApplication_8002.class, args);    }}

4.测试

进入到Eureka服务端地址,我这是127.0.0.1:9001,能够查看注册到注册核心的服务。

如图:

注意事项:Eureka通过三次心跳检测均通过,服务才会胜利注册到注册核心,默认每次距离10s,及首次启动服务需期待30s能力在Eureka中看到注册服务。

消费者搭建

1.Discover Client形式

微服务中服务既是消费者也能够是调用者,因而消费者配置和下面服务配置大体一致,依赖及配置参考下面服务端搭建形式。启动主类增加EnableEurekaClient正文:

@SpringBootApplication@EnableEurekaClient@EnableDiscoveryClientpublic class ConsumerApplication_7002 {    public static void main(String[] args) {        SpringApplication.run(ConsumerApplication_7002.class, args);    }}

外围配置类:

@Componentpublic class ConsumerDiscoveryClient {  @Autowired  private DiscoveryClient discoveryClient;  public ServiceInstance getServiceInstance() {    List<ServiceInstance> serviceInstances = discoveryClient.getInstances("licensingservice");    if (serviceInstances.size() == 0) {      return null;    }    return serviceInstances.get(0);  }  public String getUrl(String url) {    ServiceInstance serviceInstance=this.getServiceInstance();    if (serviceInstance==null)      throw new RuntimeException("404 ,NOT FOUND");    String urlR=String.format(url,serviceInstance.getUri().toString());    return urlR;  }}

通过DiscoveryClient从Eureka中获取licensingservice服务的实例数组,并返回第一个实例。

测试Controller

@RestController@RequestMapping("test")public class TestController {  //留神必须new,否则会被ribbon拦截器拦挡,扭转URL行为  private RestTemplate restTemplate=new RestTemplate();  @Autowired  private ConsumerDiscoveryClient consumerDiscoveryClient;  @RequestMapping("/getAllEmp")  public List<Emp> getAllLicense(){    String url=consumerDiscoveryClient.getUrl("%s/test/getAllEmp");    return restTemplate.getForObject(url,List.class);  }}

测试:

  1. 调试信息

从该图能够直观看到licensingservice,领有两个服务实例,并能够查看实例信息。

  1. 页面返回信息

胜利查问到数据库存储信息。

2.Ribbon性能的Spring RestTemplate形式

依赖同上。

外围配置类:

//指明负载平衡算法@Beanpublic IRule iRule() {  return new RoundRobinRule();}@Bean@LoadBalanced //通知Spring创立一个反对Ribbon负载平衡的RestTemplatepublic RestTemplate restTemplate() {  return new RestTemplate();}

设置负载平衡形式为轮询形式。

测试类:

@RestController@RequestMapping("rest")public class ConsumerRestController {    @Autowired    private RestTemplate restTemplate;    private final static String SERVICE_URL_PREFIX = "http://LICENSINGSERVICE";    @RequestMapping("/getById")    public Emp getById(Long id) {        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();        paramMap.add("id", id);        return restTemplate.postForObject(SERVICE_URL_PREFIX + "/test/getById", paramMap, Emp.class);    }}

测试后果:

  • 第一次:

  • 第二次:

  • 第三次:

因为采纳轮询负载平衡形式别离调用不同服务实例,未区别,将name做出了肯定更改。

以上两种形式比照,Ribbon形式是对第一种形式的封装且内置不同的负载算法,反对自定义。应用更加简略,但此两次均需编写RestTemplate的申请办法,较为繁琐且容易出错,第三种形式Feign客户端则极大的升高了开发难度和晋升速度。

3.feign客户端形式

引入依赖:

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

次要代码:

@FeignClient(value = "LICENSINGSERVICE",fallbackFactory = ServiceImp.class)public interface ServiceInterface {  @RequestMapping("/test/getById")  Emp getById(@RequestParam("id") Long id);  @RequestMapping("/test/getLicenseById")  License getLicenseById(@RequestParam("id") Long id);  @RequestMapping("/test/getAllEmp")  List<Emp> getAllLicense();}@Componentpublic class ServiceImp implements FallbackFactory<ServiceInterface> {    @Override    public ServiceInterface create(Throwable throwable) {        return new ServiceInterface() {            @Override            public Emp getById(Long id) {                Emp emp = new Emp();                emp.setName("i am feign fallback create");                return emp;            }            @Override            public License getLicenseById(Long id) {                return null;            }            @Override            public List<Emp> getAllLicense() {                return null;            }        };    }}

采纳接口模式开发,通过注解指明服务名以及后备办法,在服务体现不佳时,不便返回默认的后果,而不是一个不敌对的谬误。

主启动类:

@SpringBootApplication@EnableEurekaClient@EnableFeignClientspublic class Consumer_feign_Application_7004 {    public static void main(String[] args) {        SpringApplication.run(Consumer_feign_Application_7004.class, args);    }}

测试类:

@RestController@RequestMapping("rest")public class ConsumerRestController {  @Autowired  private ServiceInterface serviceInterface;  @Autowired  private RestTemplate restTemplate;  @RequestMapping("/getById")  public Emp getById(Long id) {    return serviceInterface.getById(id);  }}

测试后果:

  • 失常测试:

  • 敞开两个服务实例,模仿服务实例死亡:

Feign除了能简化服务调用,也能够实现当调用的服务失败时,敌对的反馈信息。

此三种调用形式,由低至上,从不同档次实现了SpringCloud中的微服务相互调用。