您的位置:首页 > 编程语言 > Java开发

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:6869



6.4、将服务注册到Eureka集群

服务注册到Eureka集群时,可以指定多个,也可以指定一个Eureka服务(因为Eureka服务集群间彼此互联)。

修改microservice-item的配置文件application.yml

serviceUrl: #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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: