本文次要介绍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.name
和eureka.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); }}
测试:
- 调试信息
从该图能够直观看到licensingservice
,领有两个服务实例,并能够查看实例信息。
- 页面返回信息
胜利查问到数据库存储信息。
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中的微服务相互调用。