SpringCloud构建微服务是基于SpringBoot开发的。
创建服务提供者的访问方法,消费者如何访问提供者,SpringCloud是基于rest的访问,他们之间是通过json进行交互
创建服务提供者
依赖
<!--springboot开发web项目的依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
controller
@RestController
public class HelloController {
@RequestMapping("/service/hello")
public String hello(){
// 业务处理(省略)
return "hello spring clound";
}
}
创建服务消费者
创建一个新的springboot项目
开发消费者方法,去消费服务提供者提供的服务,这个消费者方法也是一个Controller
@RestController
public class WebController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/web/hello")
public String hello(){
// 逻辑判断(省略)
// 调用SpringCloud服务提供者提供的服务(通过RestTemplate这个类远程调用服务)
return restTemplate.getForEntity("http://localhost:8080/service/hello", String.class).getBody();
}
配置RestTemplate类
//配置文件
@Configuration
public class BeanConfig {
/**
* @Bean 等价于 <bean id="restTemplate" class="xxx.xxx.RestTemplate"/>
*
* @return
*/
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
端口配置避免两个项目的端口号冲突
server.port=8081
访问
通过http://localhost:8081/web/hello
访问消费者方法,消费者方法会调用服务提供者提供的方法
Spring Cloud结构的远程调用模式
服务提供者的服务需要注册到服务中心上,消费者通过注册中心获取提供者注册的服务,然后进行调用
走进服务注册中心Eureka
微服务架构中,服务注册与发现是核心组件之一,手动指定每个服务是很低效的,SpringCloud提供多种服务注册与发现的实现方式,如:Eureka、Consul、Zookeeper。
SpringCloud支持最后的是Eureka,然后Consul、Zookeeper
服务注册
将服务所在主机、端口、版本号、通信协议等信息登记到注册中心上。
什么是服务发现?
服务消费者向注册中心请求已经登记的服务列表,然后得到某个服务的主机、端口、版本号、通信协议等信息、从而实现对具体服务的调用。
Eureka
- 一个服务治理组件,主要包括服务注册与发现,用来搭建服务注册中心
- Eureka 是一个基于 REST 的服务,用来定位服务,进行中间层服务器的负载均衡和故障转移
- Eureka 由 Netflix 提供,SpringCloud进行二次封装
- C/S 设计架构:
- Eureka Server(服务端)是服务中心;维护人员可以通过Eureka Server 来监控系统中的各个微服务是否正常运行
- Eureka Client(客户端)是一个java客户端,用于简化与服务器的交互,负载均衡,服务的故障切换等;
- 通过客户连接到服务端,并维持心跳连接;
Eureka 与 Zookeeper 的比较
CAP理论 一个分布式系统不可能同时满足cap (C:数据一致性,A:服务可用性,P:分区容错性)
- 微服务本身就分为多个节点,当一个节点出现故障时,其他节点不会随之瘫痪,这就是容错性是分布式系统必须保证的;
- 服务可用性 和 数据一致性 两者无法并存只能进行取舍,Zookeeper保证的是CP,而Eureka则是AP
Zookeeper
例如:一个Zookeeper集群,有三个节点,其中master因网络故障或与其他节点失去联系,那么Zookeeper就会在剩下的节点中选举出一个节点作为master,但是选举的过程需要时间,而这段时间整个Zookeeper集群是不可用的,也就是注册服务瘫痪,Provider无法向注册中心注册服务,这时就失去了C(服务可用性)。Zoo因网络问题导致Zookeeper失去master节点是大概率时间,虽然能回复,但是选举时间内导致服务注册长期不可用是难以容忍的。
Eureka
Eureka集群与Zookeeper不同,节点之间没有主从关系,如果某个节点挂了,剩余节点依然能提供注册和查询服务。如果Eureka Client 向 Eureka Server 注册时发现连接失败,会自动切换到其他正常的节点。但是无法保证查到的信息是最新的(不保证强一致性)
例如:
Eureka Client 向 Eureka Server 注册服务,注册完后,由于某些原因客户端停掉了该服务,这是的服务端有可能没有进行更新,导致消费者(consumer)去注册中心(Eureka Server)中获取该服务的注册信息是有的,但是调用服务的时候却无法调用的问题。
搭建并配置Eureka服务注册中心
Spring Cloud 中的Eureka 服务注册中心实际上也是一个Spring Boot工程,通过引入相关依赖和注解配置,让Spring Boot构建的微服务应用与Eureka进行整合整合。
步骤:
1.创建一个SpringBoot项目,并且添加SpringBoot的相关依赖;
(省略)
2.添加Eureka的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加Eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<!--添加依赖管理-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!--还可以配置Repository-->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
3.在Spring Boot 的入口类上添加一个@EnableEurekaServer注解,用于开启Eureka注册中心服务端
@SpringBootApplication
@EnableEurekaServer //开启Eureka注册中心服务端
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.在application.properties或yaml文件中配置Eureka服务注册中心信息
server.port=8761
#配置该服务注册中心的hostname(填ip)
eureka.instance.hostname=localhost
#由于我们目前创建的应用是一个服务注册中心,而不是普通的应用。
# 默认情况下,这个应用会向注册中心(也是它自己)注册它自己,设置为false表示禁止这种自己向自己注册的默认行为
eureka.client.register-with-eureka=false
#表示不去检索其他的服务,因为服务注册中心本身的职责就是维护服务实例,它不需要检索其他服务
eureka.client.fetch-registry=false
#指定服务注册中心的位置
eureka.client.service-url.defaultZone=http;//${eureka.instance.hostname}:${server.port}/eureka/
启动与测试Eureka服务注册中心
1.完成上面的项目搭建后,启动springboot程序,执行main方法;
2.启动成功之后,通过在浏览器地址栏访问我们的注册中心
访问界面如下:
注意
启动失败的话,肯能是SpringBoot与SpringCloud之间的兼容问题
可以通过SpringCloud官网进行访问点击跳转SpringCloud,点检Deference Doc,查看兼容版本
向Eureka服务注册中心注册服务
将服务提供者注册到Eureka注册中心
步骤
1.该服务提供者Provider添加Eureka的依赖
服务提供者想注册中心注册服务,需要连接eureka,所以需要eureka客户端的支持
<!-- 添加Eureka客户端依赖>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- 添加SpringCloud依赖管理-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.激活Eureka中的EnableEurekaClient功能:
在SpringBoot的启动类上添加@EnableEurekaClient注解来表示自己是一个Eureka Client,使得服务可用连接Eureka注册中心;
3.配置服务名称和注册中心地址
#配置服务的名称,通常与项目名一致(通过名称访问微服务)
server.servlet.context-path: /01springcloud-service-provider
#eureka的访问地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4.启动服务提供者SpringBoot程序的main方法运行
5.访问Eureka服务中心
这是就有一个服务注册上了
从Eureka服务注册中心发现和消费服务
- 服务的发现由Eureka客户端实现
- 服务的消费由Ribbon实现
- 服务的调用需要Eureka Client 和 Ribbon共同完成
Eureka Client
Eureka 客户端时一个java客户端,用来连接Eureka服务端,与服务端进行交互,负载均衡,服务的故障切换等
Ribbon
- Ribbon是基于Http 和 TCP 的客户端负载均衡器。
- 使用Ribbon对服务进行访问时,它会扩展Eureka客户端的服务发现功能,实现从Eureka注册中心中获取服务端列表,并通过Eureka客户端来确定服务端是否已经启动。
- Ribbon在Eureka客户端服务发现的基础上,实现了对服务实例的选择策略,从而实现对服务的负载均衡消费。
服务消费者调用服务提供者
1.消费者项目添加Eureka Client的依赖
consumer从注册中心获取服务,需要连接Eureka,所以需要Eureka支持
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.激活Eureka中的EnableEurekaClient功能
在启动类上添加@EnableEurekaClient注解
3.配置服务的名称和注册中心的地址
#配置服务的名称,通常与项目名一致(通过名称访问微服务)
server.servlet.context-path: /02springcloud-service-consumer
#eureka的访问地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
4.调用服务提供者时使用ribbon来调用
//配置文件
@Configuration
public class BeanConfig {
/**
* @Bean 等价于 <bean id="restTemplate" class="xxx.xxx.RestTemplate"/>
*
* @return
*/
@LoadBalanced //ribbon支持
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
加入ribbon的支持,那么调用的时候,使用服务名称来访问即可
@RestController
public class WebController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/web/hello")
public String hello(){
// Eureka + Ribbon的调用服务的方式(这种方式不再需要ip地址和端口号了)
return restTemplate.getForEntity("http://01-SPRINGCLOUD-SERVICE-PROVIDER/service/hello", String.class).getBody();
}
}
5.启动消费者程序
6.访问消费者
检验是否能正常调用