Spring Cloud入门demo笔记
2017-10-31 10:46
399 查看
1、微服务架构
近几年,微服务可以说是一个非常火的架构或者说概念,不管是大型项目,或是小公司项目,微服务架构都收到追捧。1.1、单体架构
单体架构,是指将开发好的项目打成war包,然后发布到tomcat等容器中的应用。假设你正准备开发一款与Uber和Hailo竞争的出租车调度软件,经过初步会议和需求分析,你可能会手动或者使用基于SpringBoot、Play或者Maven的生成器开始这个新项目,它的六边形架构是模块化的,架构图如下:
应用核心是业务逻辑,由定义服务、域对象和事件的模块完成。围绕着核心的是与外界打交道的适配器。适配器包括数据库访问组件、生产和处理消息的消息组件,以及提供API或者UI访问支持的web模块等。
尽管也是模块化逻辑,但是最终它还是会打包并部署为单体式应用。具体的格式依赖于应用语言和框架。例如,许多Java应用会被打包为WAR格式,部署在Tomcat或者Jetty上,而另外一些Java应用会被打包成自包含的JAR格式,同样,Rails和Node.js会被打包成层级目录。
这种应用开发风格很常见,因为IDE和其它工具都擅长开发一个简单应用,这类应用也很易于调试,只需要简单运行此应用,用Selenium链接UI就可以完成端到端测试。单体式应用也易于部署,只需要把打包应用拷贝到服务器端,通过在负载均衡器后端运行多个拷贝就可以轻松实现应用扩展。在早期这类应用运行的很好。
1.2、单体架构存在的问题
如何解决以上问题呢? – 本文的重点来了– 微服务架构。
1.3、什么是微服务
1.4、微服务架构的特征
1.5、微服务架构示例
每一个应用功能区都使用微服务完成。
2、Spring Cloud简介
2.1、简介
Spring Cloud项目的官方网址:http://projects.spring.io/spring-cloud/
2.2、Spring Cloud框架的特
4000
点
下面用一个订单微服务小栗子。订单微服务从商品微服务中获取商品信息。
3、使用Spring Boot实现微服务
在正式学习Spring Cloud之前我们先使用Spring Boot实现一个微服务。业务非常简单:
1. 商品微服务:通过商品id查询商品的服务;
2. 订单微服务:创建订单时通时,通过调用商品的微服务进行查询商品数据;
图示:
说明:
1. 对于商品微服务而言,商品微服务是服务的提供者,订单微服务是服务的消费者;
2. 对于订单微服务而言,订单微服务是服务的提供者,人是服务的消费者。
3.1、实现商品微服务
说明:本文是一个入门的例子,暂时不考虑设计的问题。
3.1.1 创建商品微服务工程
可以使用idea工具自带的spring initial 快速创建一个springboot项目
3.1.1.1、microservice-item项目结构
3.1.1.2、配置文件
server: port: 8080 spring: datasource: name: print url: jdbc:mysql://127.0.0.1:3306/springcloud-demo username: root password: root driver-class-name: com.mysql.jdbc.Driver # 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource
3.1.1.3 、创建数据库,表
创建springcloud-demo数据库,t_item商品表
3.1.2 启动测试
访问http://127.0.0.1:8080/item/1
得到数据如下:
{ id: 1, title: "商品标题1", pic: "http://picture1", desc: "商品描述1", price: 10000 }
可以看到已经通过微服务查询到数据。
3.2、订单微服务
3.2.1、创建订单微服务
3.2.1.1、microservice-order项目结构3.2.1.2、配置文件
server: port: 8081 spring: datasource: name: print url: jdbc:mysql://127.0.0.1:3306/springcloud-demo username: root password: root driver-class-name: com.mysql.jdbc.Driver # 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource
3.2.1.3、创建t_order表,t_order_detail表
t_order:
t_order_detail:
3.2.1.4 创建itemService
创建itemService去microservice-item微服务中获取商品item信息
@Service public class ItemService { // Spring框架对RESTful方式的http请求做了封装,来简化操作 @Autowired private RestTemplate restTemplate; public Item queryItemById(Long id) { return this.restTemplate.getForObject("http://127.0.0.1:8080/item/" + id, Item.class); } }
3.2.2、启动,测试
访问:http://127.0.0.1:8081/order/1
得到如下数据:
{
orderId: 1,
userId: 1,
createDate: 1509333922000,
updateDate: 1509333922000,
orderDetails: [
{
id: 1,
orderId: "1",
item: { id: 1, title: "商品标题1", pic: "http://picture1", desc: "商品描述1", price: 10000 }
},
……
{
id: 8,
orderId: "1",
item: {
id: 8,
title: "商品标题8",
pic: "http://picture8",
desc: "商品描述8",
price: 80000
}
}
]
}
成功获取到商品item信息。
3.4、解决订单系统中的url硬编码问题
通过以上的测试我们发现,在订单系统中要调用商品微服务中的查询接口来获取数据,在订单微服务中将url硬编码到代码中,这样显然不好,因为,运行环境一旦发生变化这个url地址将不可用。如何解决呢?
解决方案:将url地址写入到application.yml配置文件中。
实现:
修改application.yml文件,新增属性:
ianly: item: url:http://127.0.0.1:8080/item/
itemService中用@Value注解获取yml文件中的url链接
@Service public class ItemService { // Spring框架对RESTful方式的http请求做了封装,来简化操作 @Autowired private RestTemplate restTemplate; @Value("${ianly.item.url}") private String itemUrl; public Item queryItemById(Long id) { return this.restTemplate.getForObject(itemUrl + id, Item.class); } }
测试:
4、硬编码的问题
通过配置文件属性提取,注解获取,似乎已经解决了url硬编码的问题,但是我们想想:如果商品微服务的ip地址发生了变更,订单微服务中的配置文件也需要跟着修改
如果商品微服务有多个,那么在订单微服务中又该如何写地址?
那应该怎么解决呢? – 通过服务注册、发现的机制来完成。
5、Spring Cloud快速入门
终于到了重点了。5.1、微服务注册与发现
原理示意图:由上图可以看出:
1. 服务提供者将服务注册到注册中心
2. 服务消费者通过注册中心查找服务
3. 查找到服务后进行调用(这里就是无需硬编码url的解决方案)
4. 服务的消费者与服务注册中心保持心跳连接,一旦服务提供者的地址发生变更时,注册中心会通知服务消费者
5.2、注册中心Eureka
Spring Cloud提供了多种注册中心的支持,如:Eureka、ZooKeeper等。推荐使用Eureka。下面的实例也是以eureka为例。5.2.1、原理
Eureka官方图:Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就别一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
5.2.2、创建Eureka Server
Spring Cloud 集成了Eureka,可以很方便创建一个Eureka服务5.2.2.1、Spring Cloud依赖
<!-- 导入Spring Cloud的依赖管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- 导入Eureka服务的依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies>
5.2.2.2 Eureka服务模块结构
添加注解:
@EnableEurekaServer //申明这是一个Eureka服务
5.2.2.3 配置文件
server: port: 6868 #服务端口 eureka: client: registerWithEureka: false #是否将自己注册到Eureka服务中,本身就是所有无需注册 fetchRegistry: false #是否从Eureka中获取注册信息 serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址 defaultZone: http://127.0.0.1:${server.port}/eureka/[/code]5.2.2.4 启动与测试
访问:
http://127.0.0.1:6868
得到如下页面:5.2.3、将商品微服务microservice-item注册到Eureka
接下来,我们需要将商品的微服务注册到Eureka服务中。
第一步:修改pom文件,引入Spring Cloud的管理依赖以及eureka服务依赖。<!-- 导入Spring Cloud的依赖管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 导入Eureka服务的依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency>
第二步,修改application.yml配置文件:spring: application: name: ianly-microservice-item #指定服务名 eureka: client: registerWithEureka: true #是否将自己注册到Eureka服务中,默认为true fetchRegistry: true #是否从Eureka中获取注册信息,默认为true serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址 defaultZone: http://127.0.0.1:6868/eureka/ instance: prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
第三步,修改启动类,增加@EnableDiscoveryClient注解:
@EnableEurekaClient //申明Eureka客户端
第四步,启动与测试
访问:
http://127.0.0.1:6868
得到如下图:
至此,我们已经将自己的item微服务注册到Eureka server中了。5.3、订单系统microservice-order从Eureka发现服务
之前我们在订单系统中是将商品微服务的地址进行了硬编码,现在,由于已经将商品服务注册到Eureka中,所以,只需要从Eureka中发现服务即可。
第一步,在订单系统中添加依赖:<!-- 导入Spring Cloud的依赖管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 导入Eureka服务的依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency>
第二步,修改application.yml配置文件:spring: application: name: ianly-microservice-order #指定服务名 eureka: client: registerWithEureka: false #是否将自己注册到Eureka服务中,默认为true fetchRegistry: true #是否从Eureka中获取注册信息,默认为true serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址 defaultZone: http://127.0.0.1:6868/eureka/ instance: prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
第三步,修改ItemService的实现逻辑:@Service public class ItemService { // Spring框架对RESTful方式的http请求做了封装,来简化操作 @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; public Item queryItemById(Long id) { String serviceId = "ianly-microservice-item"; List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); if (instances.isEmpty()){ return null; } // 为了演示,在这里只获取一个实例 ServiceInstance serviceInstance = instances.get(0); String url = serviceInstance.getHost() + ":" + serviceInstance.getPort(); return this.restTemplate.getForObject("http://"+url+"/item/" + id, Item.class); } }
第四步,在启动类中添加@EnableDiscoveryClient注解
第五步,启动测试
可以看到以及获取到microservice-item微服务的地址,也能得到数据。6、注册中心Eureka
6.1、为Eureka添加用户认证
在前面的示例中,我们可以看到我们需要登录即可访问到Eureka服务,这样其实是不安全的。
接下来,我们为Eureka添加用户认证。
第一步,为microservice-eureka添加安全认证依赖:<!-- 安全认证 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
第二步,增加application.yml配置文件:security: basic: enable: true #开启基于HTTP basic的认证 user: #配置用户的账号信息 name: ianly password: ianly123
第三步,重新启动Eureka服务进行测试:
输入正确的用户名密码即可登录。
这时,服务提供者注册到Eureka时会报错,需要在服务注册时也需要设置用户名和密码。6.1.1、服务注册时设置账户信息
服务注册到有认证需求的注册中心时,需要设置如下信息:
http://USER:PASSWORD@127.0.0.1:6868/eureka/
修改application.yml配置文件:serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址 defaultZone: http://ianly:ianly123@127.0.0.1:6868/eureka/[/code]6.2、Eureka的自我保护模式
如图,当前Eureka进入了自我保护模式。
所以,一般进入自我保护模式,无需处理。如果,需要禁用自我保护模式,只需要在配置文件中添加配置即可:
enable-self-preservation: false #禁用自我保护模式
重新启动服务查看效果:
提示,如果禁用自我保护模式,在网络通信故障下会出现问题。6.3 Eureka的高可用
前面的测试,我们会发现,Eureka服务是一个单点服务,在生产环境就会出现单点故障,为了确保Eureka服务的高可用,我需要搭建Eureka服务的集群。
搭建Eureka集群非常简单,只要启动多个Eureka服务并且让这些服务之间彼此进行注册即可实现。
配置两个microservice-eureka的application.yml,相互注册文件:server:
port: 6869 #服务端口
spring:
application:
name: ianly-microservice-eureka #指定服务名
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,本身就是所有无需注册
fetchRegistry: true #是否从Eureka中获取注册信息
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址 defaultZone: http://ianly:ianly123@127.0.0.1:6868/eureka/ server:
enable-self-preservation: true #禁用自我保护模式
security: basic: enable: true #开启基于HTTP basic的认证 user: #配置用户的账号信息 name: ianly password: ianly123
======================================================================
server:
port: 6868 #服务端口
spring:
application:
name: ianly-microservice-eureka #指定服务名
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,本身就是所有无需注册
fetchRegistry: true #是否从Eureka中获取注册信息
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: http://ianly:ianly123@127.0.0.1:6869/eureka/ server:
enable-self-preservation: true #禁用自我保护模式
security: basic: enable: true #开启基于HTTP basic的认证 user: #配置用户的账号信息 name: ianly password: ianly123
重启测试
访问:
http://127.0.0.1:6868 或者 http://127.0.0.1:68696.4、将服务注册到Eureka集群
服务注册到Eureka集群时,可以指定多个,也可以指定一个Eureka服务(因为Eureka服务集群间彼此互联)。
修改microservice-item的配置文件application.ymlserviceUrl: #Eureka客户端与Eureka服务端进行交互的地址 defaultZone: http://ianly:ianly123@127.0.0.1:6868/eureka/,http://ianly:ianly123@127.0.0.1:6869/eureka/[/code]
重启测试:
访问:
http://127.0.0.1:6868 或者 http://127.0.0.1:6869
可以通过停止Eureka服务进行测试,结果会发现集群是高可用。
后续将会有集群负载的文章,敬请期待。
源码地址:https://gitee.com/ianly123/SpringCloudDemo
相关文章推荐
- Spring学习笔记-springMVC入门Demo
- QT5.10开发(2)QT入门了解及Demo介绍笔记
- Android笔记 fragment入门 动态加载fragment demo+ 判断横竖屏
- 入门Demo---SpringMVC学习笔记(二)
- 入门demo---Mybatis学习笔记(三)
- 入门demo---Mybatis学习笔记(三)
- DC学院数据分析师(入门)学习笔记----基于网页抓取天气数据demo以及基于网页抓取《摔跤吧!爸爸》豆瓣评分
- Heibernate 入门笔记(一)---第一个demo
- kinect sdk开发入门WPFdemo笔记[2] 获取深度数据
- [cocos2d-x学习笔记][入门基础]Box-2d物理引擎的使用02制作一个简易的愤怒小鸟Demo
- Spring Cloud快速入门与Demo
- 入门Demo---SpringMVC学习笔记(二)
- Django2.0 学习笔记(一)-->新手入门
- SWT入门笔记
- [原创]java WEB学习笔记45:自定义HttpFilter类,理解多个Filter 代码的执行顺序,Filterdemo:禁用浏览器缓存的Filter,字符编码的Filter,检查用户是否登陆过的Filter
- PHP入门小DEMO
- 【Visual C++】游戏开发笔记十六 讲解一个完整的回合制游戏demo
- Android/Linux Kernel 内存管理-入门笔记
- 【FacebookSDK学习笔记】Facebook官方Demo例子简单分析
- redis入门笔记(3)