SpringCloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。最重要的是,跟spring boot框架一起使用的话,会让你在开发微服务架构的云服务时非常方便。 SpringBoot旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用的微服务功能。(以上内容来自百度)
说白了,SpringCloud就是一系列可以集成在SpringBoot上的工具,来帮助开发人员实现所需的功能。SpringCloud包括的子项目有很多,那么就接此机会给大家一一分享学习各个子项目时的经验与心得。废话不多说,今天就先从Eureka讲起。
Eureka是一个基于REST的服务,主要用于AWS云中的定位服务,以实现中间层服务器的负载平衡和故障转移,在 Spring Cloud 微服务架构中通常用作注册中心,我们称这个服务为 Eureka Server,还有一个与之交互的客户端称之为 Eureka Client。
这么可能会有点抽象,下面直接上代码,听小弟娓娓道来(小弟使用的是IDEA)…
这里需要用到spring-cloud的Eureka模块,他是一个服务的注册和发现模块,我们就先新建一个项目(File==>new==>Project)
填好对应的Group、artifactId等信息点击Next
选择Spring Cloud Discovery,再选择Eureka Server,点击next==>Finish即可。
这时候我们看一下新建项目中的pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.springcloud</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>Demo project for Eureka</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- SpringBoot Web容器 -->
<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>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${
spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
这时候我们会发现它和普通的SpringBoot项目的pom.xml文件不太一样,里面多了一个Eureka-Server包(这里需要注意的是SpringCloud的版本和SpringBoot的版本是有着严格的对应关系的,我们需要对应好二者之间的版本才能正常使用)
那么我们怎么使用这个Eureka-Server包呢?其实也很简单,只需要在启动类中增加一个@EnableEurekaServer注解即可,如下代码所示:
package com.springcloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* 服务注册中心
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
接下来我们再看一下appication.yml文件
server:
port: 8081 #服务注册中心端口号
eureka:
instance:
hostname: 127.0.0.1 #服务注册中心IP地址
client:
registerWithEureka: false #是否向服务注册中心注册自己
fetchRegistry: false #是否检索服务
serviceUrl: #服务注册中心的配置内容,指定服务注册中心的位置
defaultZone: http://${
eureka.instance.hostname}:${
server.port}/eureka/
需要注意的是eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳(因此可以在内存中完成),在默认情况下erureka server也是一个eureka client ,必须要指定一个erureka server。
下面我们直接启动这个项目,在浏览器中访问http://127.0.0.1:8081
这时候我们会发现Application中显示No instances available(没有可用的实例),这是因为我们还没有进行注册,所以没有发现任何服务。接下来我们再创建一个客户端。
简单说两句,客户端在向注册中心注册时会提供一些元数据,例如主机、端口,URL等。同时注册中心(Eureka Server)也会从每个客户端(Eureka Client)接收心跳,如果心跳超时,则通常将其从注册中心删除。
Eureka Client客户端的新建方式与Eureka Server类似,只是启动类文件中的注解和appication.yml略有不同。
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:8081/eureka/ #注册中心的注册地址
server:
port: 8082 #服务端口号
spring:
application:
name: service-provider #服务名称--调用的时候根据名称来调用该服务的方法
启动类中增加@EnableEurekaClient注解,来表示这是一个客户端
package com.eurekaclient.eurekaclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 客户端
*/
@RestController
@EnableEurekaClient
@SpringBootApplication
public class EurekaclientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaclientApplication.class, args);
}
/**
* 假如这个客户端要提供一个getUser的方法
* @return
*/
@GetMapping(value = "/getUser")
@ResponseBody
public Map<String,Object> getUser(@RequestParam Integer id){
Map<String,Object> data = new HashMap<>();
data.put("id",id);
data.put("name","liziye");
data.put("date","2021-05-18");
return data;
}
}
这时候我们就可以启动客户端项目,此时我们要保证注册中心(服务端)是启动的,否则客户端在注册时访问不到注册中心地址而会报错。
客户端成功启动,也就说明客户端成功向服务端注册,此时我们再去看看服务端的页面,我们会发现Application中多了一条注册信息,也就是我们刚刚注册的信息。
眼尖的小伙伴会发现,这个页面中出现了两行红字,这个红字是提醒我们Eureka注册的服务都是高可用的,这里只检测到一个服务而产生的预警,并不会有什么影响。
刚刚我们在客户端的启动类中定义了一个getUser的方法,下面我们去访问一下这个地址http://127.0.0.1:8082/getUser?id=911
很显然咱们成功了,那么这时候可能会有人产生了一些疑问,我们提供了这么多服务,那谁来消费呢?接下来我们新建一个消费者项目。
消费者的项目和服务中心、客户端的新建方式是一样的,这里我们也就不介绍项目的建立过程了,直接上代码。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.consumer1</groupId>
<artifactId>consumer1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer1</name>
<description>Demo project for consumer1</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- SpringBoot Web容器 -->
<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>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${
spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
package com.consumer1.consumer1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@RestController
@EnableEurekaClient
@SpringBootApplication
public class Consumer1Application {
@Autowired
RestTemplate restTemplate;
public static void main(String[] args) {
SpringApplication.run(Consumer1Application.class, args);
}
/**
* 实例化RestTemplate
* @return
*/
@LoadBalanced
@Bean
public RestTemplate rest() {
return new RestTemplate();
}
/**
* 使用RestTemplate发起http请求,然后得到数据返回给前端
* @param id
* @return
*/
@GetMapping(value = "/request")
@ResponseBody
public Map<String,Object> getUser(@RequestParam Integer id){
Map<String,Object> data = new HashMap<>();
RestTemplate restTemplate = rest();
data = restTemplate.getForObject("http://service-provider/getUser?id="+id,Map.class);
return data;
}
}
下面我们启动一下消费端看看具体实现效果。
启动成功后,我们再去看看注册中心有没有新增一条信息。
我们可以看到在Application中新增了一条注册信息,也就是说我们的消费者注册成功了。下面我们再执行一下消费者中的request方法。
很显然也是执行成功了,下面重点来了,Eureka是如合实现负载均衡的呢?
我们复制一份Eureka-Client客户端,进行小小的修改(修改启动类和appication.yml文件),直接上代码。
在启动类中我们修改了getUser方法中的name值,用来进行区分。
package com.client1.client1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@EnableEurekaClient
@SpringBootApplication
public class Client1Application {
public static void main(String[] args) {
SpringApplication.run(Client1Application.class, args);
}
/**
* 假如这个客户端要提供一个getUser的方法
* @return
*/
@GetMapping(value = "/getUser")
@ResponseBody
public Map<String,Object> getUser(@RequestParam Integer id){
Map<String,Object> data = new HashMap<>();
data.put("id",id);
data.put("name","yangyawang");
data.put("date","2021-05-18");
return data;
}
}
eureka:
client:
serviceUrl: #注册中心的注册地址
defaultZone: http://127.0.0.1:8081/eureka/
server:
port: 8088 #服务端口号--该端口不要冲突
spring:
application:
name: service-provider #服务名称--调用的时候根据名称来调用该服务的方法--名字绝对不能改,改了就访问不到了
修改完成后,我们启动这个新的项目,启动完成后我们会发现注册中心中这一条信息出现了两个实例。
那么我们分别访问一下Service-provider中的两个实例,看看是什么效果呢?
我们可以清楚的看到8082端口,name是liziye;8088端口,name是yangyawang
这时候可能很多小伙伴要好奇了,那我们访问一下消费者的地址会是一个什么情况呢?下面为大家揭晓谜底…
我们可以看到刚开始访问http://127.0.0.1:8083/request?id=911的时候,出现的name值是yangyawang,当我们刷新一次后name值就变成了liziye,这也就说明了两台服务的提供者在交替工作,从而达到了一个负载均衡的作用。
下面为大家放上一张Eureka架构图,看了上面的讲解以后,再去看这张架构图是不是就更好理解了呢
Spring Cloud 对于中小型互联网公司来说是一种福利,因为这类公司往往没有实力或者没有足够的资金投入去开发自己的分布式系统基础设施,使用 Spring Cloud 一站式解决方案能在从容应对业务发展的同时大大减少开发成本。随着近几年微服务架构和 Docker 容器概念的火爆,也会让 Spring Cloud 在未来逐渐“云”化的软件开发风格中立有一席之地。
以上就是本人在学习Eureka时的一些经验心得,整理后拿出来跟大家分享一下,后续会不定期的继续跟大家分享Spring Cloud的其他服务应用。
如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。
你在被打击时,记起你的珍贵,抵抗恶意;
你在迷茫时,坚信你的珍贵,抛开蜚语;
爱你所爱 行你所行 听从你心 无问东西