(一):必要的理论知识
Spring Cloud简介
Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。
Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud0 CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI等项目。
微服务架构
“微服务架构”在这几年非常的火热,以至于关于微服务架构相关的开源产品被反复的提及(比如:netflix、dubbo),Spring Cloud也因Spring社区的强大知名度和影响力也被广大架构师与开发者备受关注。
那么什么是“微服务架构”呢?简单的说,微服务架构就是将一个完整的应用从数据存储开始垂直拆分成多个不同的服务,每个服务都能独立部署、独立维护、独立扩展,服务与服务间通过诸如RESTful API的方式互相调用。
(二):个人对微服务的粗浅理解
目前我对微服务还处于刚入门阶段,我这里记录下我此时对微服务的粗浅理解(不一定对,希望大家指正哈)。微服务是为了解耦以及服务复用而存在的。比如,大多数系统都有用户注册模块,那么我们可以将用户注册模块作为一个单独的微服务抽离出来(此处仅作为举例)。微服务的实现可以分成三个模块,画个示意图如下
从图中我们可以看出,一个微服务架构可以分成三个模块,一个服务的注册中心,一个是服务的客户端(即属于EurekaClient项目),另一个则是提供所有微服务(具体的业务,如用户注册逻辑)的模块。当我们把所有的微服务注册到注册中心之后,我们需要建立一个属于EurekaClinet的项目,可以通过DiscoveryClient中的api方法来调用所注册的服务。这样整个流程走通。下面我们具体代码实现一下
(三):具体代码实现
本次实现使用Eureka。它是从属于Spring Cloud Netflix (包含服务发现、断路器和监控、智能路由、客户端负载均衡)的子项目。
基于我粗浅的理解,下面我们具体实现一下。我们需要建立至少三个springboot工程,一个是服务注册中心Eureka-server,一个myweb(EurekaClient工程),还有一个是用户注册的微服务(userreg)。
下面我们使用Intellij idea中的Spring Initializr来快速构建Spring Boot/Cloud工程(这个网上可以搜索到,此处就不赘述了)。
我们分别来看下三个工程的代码结构
-
eureka-server工程:
pom文件:我们需要引入spring-cloud-starter-eureka-server依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jshh</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>1.5.4.RELEASE</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</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>
</project>
配置文件application.properties,注释写的很清楚
pring.application.name=eureka-server
server.port=8761
#在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
#eureka.instance.hostname=localhost
#关闭保护机制,以确保注册中心将不可用的实例正确剔除
eureka.server.enable-self-preservation=false
启动类,注意添加@EnableEurekaServer注解,表示该工程为Eureka服务注册中心
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
-
某个微服务,此处我们举例userreg用户注册
pom文件,注意此时的spring-cloud-starter-eureka依赖没有server哦
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jshh</groupId>
<artifactId>userreg</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>userreg</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件application.properties
server.port=9001
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8761/eureka/
spring.application.name=userreg
#如果是IP地址(我们暂时没有域名,则加入)
eureka.instance.preferIpAddress=true
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
启动类,注意EnableDiscoveryClient注解,表示能被EurekaClient发现的微服务
@SpringBootApplication
@EnableDiscoveryClient
public class UserregApplication {
public static void main(String[] args) {
SpringApplication.run(UserregApplication.class, args);
}
}
业务类,如UserController,表示逻辑操作注册
@RestController
public class UserController {
@RequestMapping("/reg")
public Map<String,String> reg()
{
Map<String,String> map=new HashMap<String, String>();
map.put("status","用户注册成功");
return map;
}
}
-
myweb工程:对外提供接口数据的客户端
pom文件,注意spring-cloud-starter-eureka依赖没有server哦
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jshh</groupId>
<artifactId>myweb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>myweb</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>1.5.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件application.properties,注意配置文件中,该工程是对外提供接口的,所以他不需要将自己注册到服务端,这和userreg工程是不同的
server.port=9050
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
#不需要把自己注册到服务端
eureka.client.register-with-eureka=false
启动类,注意注解EnableEurekaClient,表示他是作为EurekaClient的工程,这样就可以从注册中心获取注册的微服务来进行调用了
@SpringBootApplication
@EnableEurekaClient
public class MywebApplication {
public static void main(String[] args) {
SpringApplication.run(MywebApplication.class, args);
}
}
业务类,我们使用DiscoveryClient类来从注册中心获取到USERREG微服务的实例,此处为什么是List<ServiceInstance>集合呢?我们后面几篇文章会解答。暂时我们可以知道同一个服务名称可以有很多实例,为后面负载均衡埋下伏笔。
@RestController
public class Myweb {
@Autowired
DiscoveryClient discoveryClient;
@RequestMapping("/userreg")
public Map userreg() {
List<ServiceInstance> list = discoveryClient.getInstances("USERREG");
String serviceUrl = list.get(0).getUri().toString();
System.out.println(serviceUrl);
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject(serviceUrl + "/reg", Map.class);
}
}
我们分别启动三个工程后,
访问
服务注册中心:http://localhost:8761/
http://localhost:9050/userreg myweb这个是对外提供接口的地址,就是给前端调用
http://localhost:9001/reg userreg这个一般不对外提供,可以部署在内网
我们来看下服务注册中心访问之后是什么样子?
至此我们完成了微服务的注册以及服务之间的调用。
微服务流行的原因我觉得是解决了系统日渐复杂,数据空前增大,并发激增的问题。后面我们会继续学习微服务。
预告一下:下一篇我们会学习Eureka的自我保护以及健康检查