最近公司在推广spring cloud,之前只是听闻spring cloud大名,并没有实际在开发使用过,为了能更快接入spring cloud到项目中,自己学习并将学习过程进行整理,做一个spring cloud系列 。
前戏
学习spring cloud 必须对springboot有一定了解,因为spring cloud是基于spring boot作为基础框架,这里就不在赘述springboot 的使用。
- spring cloud 简介
一般学习一项技术第一个选择路径就是去官网(https://spring.io/projects/spring-cloud)看文档,虽然英语不好,但是通过翻译也知道个大概。也就是springcloud 提供了一系列快速构建分布式系统的工具(配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁定,领导选举,分布式会话,集群状态),适用于任何分布式环境。我们今天就是简单介绍服务发现的使用,其实spring cloud服务发现工具有很多可以用zokeeper、eureka等,这篇文章使用eureka作为服务发现工具。
- eureka 简介
同样我们可以去官网去看看https://github.com/Netflix/eureka
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
这里我给出Eureka官网给出的架构图,并做一点简单解释,让我们对微服务或者eureka服务架构有一定了解。
直奔主题
在开始写代码之前先了解一下服务注册与发现,使用过 dubbo应该很熟悉下面这张图,其中注册中心、服务提供端、服务消费端是各种服务发现必有的模块,我们今天的spring cloud基本也基于此架构
今天我们项目的简单架构入下图,我们使用spring cloud 因为Eureka作为注册中心(Eureka server),两个服务组件用户服务和积分服务,再用户服务通过用户id调用积分服务中对应用户的积分。
搭建spring cloud 注册中心服务
建立springboot项目,需要注意的是spring cloud版本各种各样,需要根据springcloud版本使用对于springboot版本,有些版本间是不兼容的,我们可以参考spring官网给出的版本关系进入依赖https://spring.io/projects/spring-cloud。
- 引入依赖
UTF-8
UTF-8
1.8
2.0.0.RELEASE
Finchley.SR1
org.springframework.cloud
spring-cloud-starter
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
2.作为注册中心启动
@SpringBootApplication
@EnableEurekaServer
public class SpringcloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudApplication.class, args);
}
}
- 配置
server:
port: 8888
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false # 这两个属性 作为注册中心时关闭其作为客户端去寻找注册的功能
fetchRegistry: false #
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
spring:
jmx:
default-domain: eureka-server
application:
name: eureka-server
4.启动项目,访问https://localhost:8888出现下面页面,第一步注册中心就这样搭建成功。
积分服务(score client)搭建
- 引入依赖,只需要将上面Eureka server依赖更换为client依赖
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-web
2.核心代码
- 启动类
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudApplication.class, args);
}
}
- 获取积分的rest接口
@RestController
@RequestMapping("/score")
public class TestController {
private static Logger logger = LoggerFactory.getLogger(TestController.class);
/** 模拟数据库: demo 为了简单方便使用HashMap模拟查询数据库 */
private static HashMap scoreDb = new HashMap<>();
static {
scoreDb.put(1,"100");
scoreDb.put(2,"88");
scoreDb.put(3,"99");
scoreDb.put(4,"90");
scoreDb.put(5,"93");
}
@GetMapping("/get/{id}")
public String test(@PathVariable String id){
String score = scoreDb.get(id);
System.err.println("查询"+ id +"分数:"+ score);
return score;
}
}
3.配置
server:
port: 8800
eureka:
instance:
hostname: localhost
client:
# registerWithEureka: false # 作为client端是 这两个使用默认值
# fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:8888/eureka # eureka 服务注册中心地址,刚才启动的注册中心地址
spring:
jmx:
default-domain: score
application:
name: score-client
4.启动,在注册中心查看服务是否被发现
用户(user client)服务搭建
1、2步同上;
- 配置
server:
port: 8802
eureka:
instance:
hostname: localhost
client:
# registerWithEureka: false 作为服务client 这两项默认(true)即可
# fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:8888/eureka # eureka 服务注册中心地址
spring:
jmx:
default-domain: user
application:
name: user-client
4.配置RestTemplate远程调用,其中使用@LoadBalanced注解进行负载均衡,下篇文章具体讲负载均衡的实现以及负载均衡策略自定义
@Configuration
public class BootConfig {
private static Logger logger = LoggerFactory.getLogger(BootConfig.class);
@Bean
//此注解主要是开启负载均衡,在http调用时会将url根据Eureka 服务中实例做转换,并可以进行应 用端负载均衡
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
5.启动类配置和上面client一样
/**
* spring cloud 客户端
*
* @author tongqingbo
*/
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudApplication.class, args);
}
}
6.通过用户获取分数rest接口,需要注意的是我们不是采用直接调用真实的接口地址,而是使用eureka中注册的服务实体名,前提是需要在IOC注入的时候加 @LoadBalanced注解实现负载均衡,要不不能使用实体名访问;
@RestController
@RequestMapping("/user")
public class TestController {
private static Logger logger = LoggerFactory.getLogger(TestController.class);
@Autowired
RestTemplate restTemplate ;
@GetMapping("/getScore/{userId}")
public String test(@PathVariable() String userId){
// 此处调用地址在单体架构中可以直接使用IP:Port接口地址进行直接调用,那其实就体现不出来服务注册的作用了,这里的score-client就是在注册服务上的实体名称,可以简单理解为注册服务帮你做了映射
String forObject = restTemplate.getForObject("http://score-client/score/get/"+userId, String.class);
return userId+ "获取积分: " + forObject;
}
}
7.在服务注册页面查看此客户端已成功注册
在页面上调用user-client接口查看分数,可以成功查看;
总结:
其实spring cloud 就是一套分布式服务的工具集,此篇文章我们只是介绍服务注册、发现,其实在没有集群或者多网域的情况下我们不使用服务注册直接调用真实接口地址也是可行的,就像前后端分离一样直接调用接口,但是在集群情况下我们可以通过注册中心对服务进行管理;进行负载均衡、熔断、网关等实现高可用的服务。关于微服务的其他工具使用在后面也会慢慢讲到,我也是一边学习一边总结如果文中有什么描述不当或者理解错误的地方欢迎各位大佬批评指导。
补充
大家可以试一下,当注册中心宕机后其实服务还是能正常访问的,因为当一次访问成功后在客户端会有缓存这个调用地址,注册中心挂掉其实也不会立马导致服务功能无法实现,当然注册中心挂掉后我们应该及时处理问题,或者一般情况下核心服务节点都会做集群处理这样倒下一个服务器还有千千万万个服务器。
补充2,所有eureka client 在启动类的注解@EnableEurekaClient可以省略,springboot会自定配置进行EurekaClient的初始化配置。