基础理论讲解、骨架搭建和演示案例编写
从今天起,我会每3日更新一个章节的内容,来剖析Spring Cloud的使用和主要组件的源码分析,分析的内容会伴随着使用过程的深入来进行,因为Spring Cloud本身是一个非常庞大的框架集合,内容多到令人发指,在Github上都是一个专门的账号来托管Spring Cloud的源代码。(本教程是假设你已经具备了Java基础编程能力,并懂得传统MVC系统开发的基础上来进行学习的,如果这些你都还不会,可能这个系列教程并不适合你,如果我后续有空,会写一些基础教程。)
其中的仓库数量截止到撰文这一刻已经达到98个,所以我们不可能剖析完整的Spring Cloud源代码,因为数量实在是太庞大,本文仅剖析主要部分的核心代码,以便让我们能够更加清楚Spring Cloud的主要部件都是如何工作的。
既然要解析,我们直接上源码估计你也吃不消,那么我们就从最简单的Demo入手,一步步的将其掰开了、揉碎了,帮助大家消化。那么下面我们就开始本系列文章的第一步:《Demo的搭建和基础理论讲解》。
文章目录
前言
首先,我们要清楚Spring Cloud到底是个啥!下面,我们来看一下维基百科上对其的解释:
简介:微服务(英语:Microservices)是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic)的API集相互通信。
微服务的起源是由 Peter Rodgers 博士于 2005 年度云计算博览会提出的微 Web 服务(Micro-Web-Service)开始,Juval Löwy 则是与他有类似的前导想法,将类别变成细粒服务(granular services),以作为微软下一阶段的软件架构,其核心想法是让服务是由类似 Unix 管道的访问方式使用,而且复杂的服务背后是使用简单 URI 来开放接口,任何服务,任何细粒都能被开放(exposed)。这个设计在 HP 的实验室被实现,具有改变复杂软件系统的强大力量。
2014年,Martin Fowler 与 James Lewis 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的行程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用HTTP API通信。同时服务会使用最小的规模的集中管理 (例如 Docker) 能力,服务可以用不同的编程语言与数据库等组件实现。
概念:微服务是一种以业务功能为主的服务设计概念,每一个服务都具有自主运行的业务功能,对外开放不受语言限制的 API (最常用的是 HTTP),应用程序则是由一个或多个微服务组成。
微服务的另一个对比是单体式应用程序。单体式应用表示一个应用程序内包含了所有需要的业务功能,并且使用像主从式架构(Client/Server)或是多层次架构(N-tier)实现,虽然它也是能以分布式应用程序来实现,但是在单体式应用内,每一个业务功能是不可分割的。若要对单体式应用进行扩展则必须将整个应用程序都放到新的运算资源(如:虚拟机) 内,但事实上应用程序中最吃耗费资源、需要运算资源的仅有某个业务部分(例如跑分析报表或是数学算法分析),但因为单体式应用无法分割该部分,因此无形中会有大量的资源浪费的现象。
微服务运用了以业务功能的设计概念,应用程序在设计时就能先以业务功能或流程设计先行分割,将各个业务功能都独立实现成一个能自主运行的个体服务,然后再利用相同的协议将所有应用程序需要的服务都组合起来,形成一个应用程序。若需要针对特定业务功能进行扩展时,只要对该业务功能的服务进行扩展就好,不需要整个应用程序都扩展,同时,由于微服务是以业务功能导向的实现,因此不会受到应用程序的干扰,微服务的管理员可以视运算资源的需要来配置微服务到不同的运算资源内,或是布建新的运算资源并将它配置进去。
虽然使用一般的服务器虚拟化技术就能应用于微服务的管理,但容器技术 (Container Technology) 如 Docker 会更加地适合发展微服务的运算资源管理技术。
原文出处:https://zh.wikipedia.org/wiki/%E5%BE%AE%E6%9C%8D%E5%8B%99
不拉不拉的一大段话下来,大家有没有形成一点概念呢?如此专业的解释,我就不用自己的话描述了,已经有现成的解释,并且解释的非常到位,还不懂?那么今天的内容就可以带你入门,让你知道到底什么是微服务。
一、微服务是什么?
微服务本身更像一个规范,而并非我们其他熟知的解决某一特定业务的框架。它是面向现金越来越复杂的大型系统的解决方案,他是服务与整个高性能系统搭建的解决方案,并不只是像大家所熟悉的spring-core、spring-mvc、mybatis一样,仅仅是为了解决大家编码过程中访问数据库、处理servlet和控制IOC/DI这些片面性的框架了。所以,Spring Cloud的框架层级上升了几个Level,难度自不必讲,并且Spring Cloud并不是一个框架,他是一堆开源技术框架的整合,并提供了相应的开发规范来让使用者按照约定的规范进行开发,Spring Cloud并没有重复造轮子,他只是将不同的、经过验证的技术进行了整合,并提供了一套完整的统一API接口给我们。只要使用这套接口,你就可以搭建出一整套微服务系统。那么也就是说Spring Cloud就是微服务概念的一整套实现,当然还包括第二代的Spring Cloud Alibaba,这里先不提第二代的微服务系统,本文还是以第一代的基于Netflix技术的Spring Cloud进行讲解。
二、Demo编写
1.创建工程并配置项目主POM
首先,请使用你自己习惯的IDE来创建一个Maven子工程形式的项目,本文全程采用IntellijIDEA进行编写。JDK使用的是最新的JDK-15,并启用了里面的新功能,请根据自己的情况适当调整。
1.1 主工程pom.xml
这里,我们先从主工程的pom.xml开始,子工程的内容我会一步步的解释,首先我们打开工程根目录下面的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">
<modelVersion>4.0.0</modelVersion>
<!-- 继承Spring Boot Starter的父工程依赖,并且在这里
指定整个Spring Boot工程的版本,在后续的子工程中
将不再指定Spring Boot的版本信息,将版本控制交给
Parent去处理,最大限度的解决和Spring Cloud的版
本冲突问题 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
</parent>
<!-- 本Demo工程的版本信息 -->
<groupId>com.richie696</groupId>
<artifactId>spring-cloud-eureka-demo</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<!-- 本Demo工程的子模块 -->
<modules>
<module>eureka-demo-parent</module>
<module>eureka-demo-registry</module>
<module>eureka-demo-provider</module>
<module>eureka-demo-consumer</module>
</modules>
<!-- 全局的属性定义 -->
<properties>
<file.encoding>UTF-8</file.encoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
</properties>
<!-- 私服配置 -->
<repositories>
<!-- 阿里云公共仓库,该仓库地址合并了maven中央仓库(central)和
jcenter 仓库的所有内容,所以严重推荐大家使用该仓库进行国内
的仓库访问加速服务。 -->
<repository>
<id>aliyunmaven</id>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<!-- Spring阿里云加速镜像 -->
<repository>
<id>spring</id>
<url>https://maven.aliyun.com/repository/spring</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<!-- Spring Plugin阿里云加速镜像 -->
<repository>
<id>spring-plugin</id>
<url>https://maven.aliyun.com/repository/spring-plugin</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>
工程主pom当中就配置这么多内容了,剩下和工程本身有关的配置都放在eureka-demo-parent当中,eureka-demo-parent作为本Demo的核心配置文件使用,而工程的主pom.xml用于和Spring Boot Starter建立联系,以及配置站点镜像来提速使用。以区分边缘配置内容和项目本身的依赖管理,这样能够让我们更清晰的进行项目配置。
1.2 eureka-demo-parent/pom.xml
首先,我们打开eureka-demo-parent工程,这是我们Demo项目用来管理依赖配置的工程,其他所有的子模块都继承该工程,那么下面我们就开始配置该pom,废话不多说,直接上代码,具体的解释都在pom.xml当中
eureka-demo-parent/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">
<!-- 改工程继承自Demo工程的主pom文件 -->
<parent>
<artifactId>spring-cloud-eureka-demo</artifactId>
<groupId>com.richie696</groupId>
<version>1.0.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 指定当前子工程打包时作为pom文件方式进行打包 -->
<packaging>pom</packaging>
<artifactId>eureka-demo-parent</artifactId>
<build>
<plugins>
<!--打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 项目编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>15</source>
<target>15</target>
<encoding>UTF-8</encoding>
<!-- 编译时保存方法参数名称(启用该设置以后参数名就不会变成arg0、arg1……) -->
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 生成Javadoc文档的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<charset>UTF-8</charset>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>snapshots</id>
<phase>deploy</phase>
</execution>
<execution>
<id>releases</id>
<phase>deploy</phase>
</execution>
</executions>
</plugin>
<!-- 打包源代码的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<attach>true</attach>
<excludeResources>true</excludeResources>
</configuration>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- 对依赖版本进行集中管理 -->
<dependencyManagement>
<dependencies>
<!-- Spring Cloud的版本不能乱用,必须和Spring Boot版本对应上,具体可以
查看Spring Cloud官网的 Reference Doc. 请先确定要使用的Cloud版本。
https://spring.io/projects/spring-cloud-config#learn-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Demo的公共定义域模块,包含pojo、enums、utils等 -->
<dependency>
<groupId>com.richie696</groupId>
<artifactId>eureka-demo-domain</artifactId>
<!-- 这里请不要是用写死的版本号,否则后续维护版本号会很麻烦 -->
<version>${project.version}</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<!-- 单元测试相关依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!-- 工具类包相关依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- 以下是Spring Cloud需要用到的包 -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 这里指定整个工程都可能会依赖使用到的包,
如果不是全局使用的,请配置在子工程内 -->
<dependencies>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--⽇志依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Actuator可以帮助你监控和管理Spring Boot应⽤-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</dependency>
</dependencies>
</project>
1.3 eureka-demo-domain/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模块,所有的依赖都从parent里面要 -->
<parent>
<artifactId>eureka-demo-parent</artifactId>
<groupId>com.richie696</groupId>
<version>1.0.0-RELEASE</version>
<relativePath>../eureka-demo-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 指定当前子模块打包成jar包 -->
<packaging>jar</packaging>
<artifactId>eureka-demo-domain</artifactId>
<dependencies>
<!-- 数据库访问采用data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
</project>
至此,我们基础模块配置就差不多了。下面我们需要对最主要的和业务有关的3个包进行配置了,这里我们先说明一下3个包的作用。
- eureka-demo-registry:Eureka注册中心的包(Eureka和Zookeeper不一样,他需要自己编写项目来启动,而并非一个独立产品。)
- eureka-demo-provider:服务提供者,也就是业务逻辑的处理包,类似于传统开发中的service包;
- eureka-demo-consumer:服务消费者,provider提供的服务就是给consumer用的,consumer就是终端消费者。你可以将其理解为传统开发中的controller层,用来接收客户端请求,再将请求提交给provider进行处理,之后将provider的处理结果再进行加工后返回给客户端。
所以,我们想要编写provider和consumer就必须先将registry工程弄好。下面我们就开始进行registry子模块的配置。
1.4 eureka-demo-registry/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模块,所有的依赖都从parent里面要 -->
<parent>
<artifactId>eureka-demo-parent</artifactId>
<groupId>com.richie696</groupId>
<version>1.0.0-RELEASE</version>
<relativePath>../eureka-demo-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 指定当前子模块打包成jar包 -->
<packaging>jar</packaging>
<artifactId>eureka-demo-registry</artifactId>
<dependencies>
<!-- Eureka server依赖引用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 新版Cloud开始需要配置config包,老版本不需要 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
1.5 eureka-demo-provider/pom.xml
下面开始配置服务提供者的依赖,因为会涉及到数据库访问,以及eureka服务发布,所以需要依赖的包内容要多一点,具体内容参考下文:
<?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模块,所有的依赖都从parent里面要 -->
<parent>
<artifactId>eureka-demo-parent</artifactId>
<groupId>com.richie696</groupId>
<version>1.0.0-RELEASE</version>
<relativePath>../eureka-demo-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 指定当前子模块打包成jar包 -->
<packaging>jar</packaging>
<artifactId>eureka-demo-provider</artifactId>
<dependencies>
<!-- 公共域模块的引用 -->
<dependency>
<groupId>com.richie696</groupId>
<artifactId>eureka-demo-domain</artifactId>
</dependency>
<!-- data-jpa的引用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql驱动的引用 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Eureka server依赖引用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 新版Cloud开始需要配置config包,老版本不需要 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
1.6 eureka-demo-consumer/pom.xml
consumer包因为需要从注册中心中获取provider的信息来进行调用,所以他不需要通过模块依赖的形式来引入provider的相关内容,具体配置如下:
<?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模块,所有的依赖都从parent里面要 -->
<parent>
<artifactId>eureka-demo-parent</artifactId>
<groupId>com.richie696</groupId>
<version>1.0.0-RELEASE</version>
<relativePath>../eureka-demo-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 指定当前子模块打包成jar包 -->
<packaging>jar</packaging>
<artifactId>eureka-demo-consumer</artifactId>
<dependencies>
<!-- 公共域模块的引用 -->
<dependency>
<groupId>com.richie696</groupId>
<artifactId>eureka-demo-domain</artifactId>
</dependency>
<!-- Eureka server依赖引用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 新版Cloud开始需要配置config包,老版本不需要 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
2 Spring Boot 配置
2.1 Registry注册中心配置
至此,我们就配置好了所有的pom文件,后续还需要用到哪些依赖,再额外配置即可。下面我们就开始编写eureka-demo-registry注册中心子模块的代码和配置了。实际上也没有代码,主要是application.yml配置。废话不多说,直接上代码:
spring:
application:
//
name: eureka-demo-registry
eureka:
dashboard:
# 启用eureka控制台页面(默认:true,可以不配置)
enabled: true
client:
# 禁止eureka server自身当做服务注册
register-with-eureka: true
# 屏蔽eureka server自身的注册信息
fetch-registry: true
server:
# 开启自我保护模式(默认:true,可以不配置)
enable-self-preservation: true
---
# eureka 注册中心实例1
spring:
config:
activate:
on-profile: registry-instance-1
server:
port: 8901
eureka:
instance:
# 请在本地host当中增加主机名称映射,否则无法模拟单机集群环境
hostname: registry1.myapp.com
client:
service-url:
defaultZone: http://registry2.myapp.com:8902/eureka,http://registry3.myapp.com:8903/eureka
---
# eureka 注册中心实例2
spring:
config:
activate:
on-profile: registry-instance-2
server:
port: 8902
eureka:
instance:
# 请在本地host当中增加主机名称映射,否则无法模拟单机集群环境
hostname: registry2.myapp.com
client:
service-url:
defaultZone: http://registry1.myapp.com:8901/eureka,http://registry3.myapp.com:8903/eureka
---
# eureka 注册中心实例3
spring:
config:
activate:
on-profile: registry-instance-3
server:
port: 8903
eureka:
instance:
# 请在本地host当中增加主机名称映射,否则无法模拟单机集群环境
hostname: registry3.myapp.com
client:
service-url:
defaultZone: http://registry1.myapp.com:8901/eureka,http://registry2.myapp.com:8902/eureka
这里因为需要单机模拟Eureka集群环境,所以需要在application.yml里面模拟出3台设备的配置,然后通过on-profile指定启动时需要加载的配置信息,并在配置的hostname当中指定本地映射的3个域名,如下:
至此,配置就结束了。
2.2 编写注册中心启动配置和类
下面只需要在Reigstry工程里面创建一个Spring Boot的入口类,并增加注解就可以启动注册中心了。代码如下:
package com.richie696.registry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaRegistry {
public static void main(String[] args) {
SpringApplication.run(EurekaRegistry.class, args);
}
}
这里,我们在第二节中会详细解释 @EnableEurekaServer 和 @EnableEurekaClient 这2个注解的作用,我们整个工程之所以会被标识为EurekaServer或EurekaClient,都是因为这2个注解。Eureka实际上是不分主从的,它采用的是对等节点,具体的下一章再做解释。
下面启动注册中心,请分别在IDEA当中配置3个应用程序,具体如下:
在活动配置文件这里填写application.yml当中
spring.config.activate.on-profile: registry-instance-[实例编号]
这里的配置名称。然后依次启动这3个实例即可。下面就可以访问Eureka的控制台来查看实例信息了。这里我访问的是1号实例的控制台,你也可以访问其他实例的控制台,这都无关紧要,访问地址就是:
http://localhost:8901 或 http://registry1.myapp.com:8901/
http://localhost:8902 或 http://registry2.myapp.com:8902/
http://localhost:8903 或 http://registry3.myapp.com:8903/
具体的解释请看截图,这里我就不码字详细解释了,我想图上的注释写的已经很明确了,只要你本地的实例启动以后和我的一样,就证明启动成功了。下面剩下的只是编写剩余的案例代码即可。
3 编写演示代码
演示代码在 eureka-demo-provider 和 eureka-demo-consumer 当中,我们编写一个最简单的登陆的请求。
下面是登录信息的建库脚本:
DROP SCHEMA IF EXISTS `sc-demo`;
CREATE SCHEMA `sc-demo` DEFAULT CHARACTER SET utf8mb4;
USE `sc-demo`;
CREATE TABLE `sc-demo`.`account_info` (
`id` INT NOT NULL COMMENT '主键列',
`login_name` VARCHAR(45) NOT NULL COMMENT '登录账号名',
`login_password` VARCHAR(32) NOT NULL COMMENT '登录密码',
`password_token` VARCHAR(32) NOT NULL COMMENT '密码令牌',
`user_name` VARCHAR(45) NOT NULL COMMENT '用户姓名',
`age` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户年龄',
`status` MEDIUMINT NOT NULL COMMENT '用户状态标识',
`version` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
`created_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`deleted_flag` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标识(1 - 删除,0 - 未删除)',
PRIMARY KEY (`id`)
) COMMENT '账户信息表';
请自行在provider当中编写一个登录验证的逻辑代码,从控制器层到dao层全部按照传统编码方式进行编码,控制器注解请使用@RestController,这里就不展示代码细节了,文章末尾会提供我案例中的Demo给大家。代码结构如下:
等业务完全编写完毕以后,创建一个SpringBoot的启动引导类,具体代码如下:
package com.richie696.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EntityScan("com.richie696.**.domain")
@EnableDiscoveryClient
public class LoginServiceProvider {
public static void main(String[] args) {
SpringApplication.run(LoginServiceProvider.class, args);
}
}
@SpringBootApplication:标识当前是一个SpringBoot应用;
@EntityScan(“com.richie696.**.domain”):扫描指定包下面的所有实体类(JPA的注解)
@EnableDiscoveryClient:启用服务发现功能,新版本的Spring Cloud已经默认加载了,后续会说到。这里也可以不设置该注解,但是建议写上。编写好以后,启动该工程。然后再去Eureka注册中心管理页面上就可以看到该服务实例上线了。
最后,编写consumer代码进行服务调用。这里需要注意的是在客户端创建调用的时候引入DiscoveryClient的时候需要引入Spring Cloud包下面的DiscoveryClient,而不是netflix包下的。
错误的引用:com.netflix.discovery.DiscoveryClient;
正确的引用:org.springframework.cloud.client.discovery.DiscoveryClient;
具体客户端代码和application.yml配置如下,yml的配置和provider差不多。
application.yml
server:
port: 9000
spring:
application:
name: remote-consumer
eureka:
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
client:
service-url:
defaultZone: http://registry1.myapp.com:8901/eureka,http://registry2.myapp.com:8902/eureka,http://registry3.myapp.com:8903/eureka
# 每隔指定时间从服务中心获取最新列表到本地,并刷新本地缓存(默认:30秒,此处一般无需配置也无需修改)
registry-fetch-interval-seconds: 30
远程消费者客户端调用代码示例:
package com.richie696.demo.account.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/remote")
public class RemoteController {
private final RestTemplate restTemplate;
private final DiscoveryClient discoveryClient;
@Autowired
public RemoteController(RestTemplate restTemplate, DiscoveryClient discoveryClient) {
this.restTemplate = restTemplate;
this.discoveryClient = discoveryClient;
}
@GetMapping("/login/{name}/{password}")
public String login(@PathVariable String name, @PathVariable String password) {
// 从Eureka注册中心中根据服务提供者的名称获取服务主机的元数据信息列表
List<ServiceInstance> instances = discoveryClient.getInstances("LOGIN-SERVICE-PROVIDER");
// 如果当前没有可用列表则终止执行
if (instances.isEmpty()) {
return "当前无可用服务。";
}
/*
否则获取一个实例(这里先不用负载均衡,我们后续
会将该案例逐步升级,一步步告诉你为什么要这么做,
我们现在就从最简单的代码开始)
*/
ServiceInstance serviceInstance = instances.get(0);
// 生成服务提供者实例的主机地址
String hostName = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url = String.format("http://%s:%s/account/login/%s/%s", hostName, port, name, password);
System.out.printf("# 主机地址: %s%n", url);
// 调用远程服务并返回结果
return restTemplate.getForObject(url, String.class);
}
}
最后,创建一个consumer的Spring boot引导类并执行,如果可以正确获得如下信息,即表示案例已经编写成功,后续的教程中会一步步演变。
至此,我们已经完成了阶段一的任务,请消化一下上面的代码,代码并没有一口气直接上全微服务的组件,而是会在后续课程中一个个的增加上去,以便于对主要组件的源代码一个个的进行解析。过几天我会发出第二篇内容,第二篇开始会针对当前的案例开始进行Eureka的源代码解析。本篇案例的源码下载地址如下:
GITHUB地址:https://github.com/richie696/spring-cloud-eureka-demo [建议大家watch或star该地址,后续课程的源码更新也会提交在这里面,并且以分支点形式进行提交。]
强烈建议大家按照整个流程自己写一遍演示案例,并分析一下代码的结构写上注释,如果有任何问题,可以回帖问我,我看到了会为大家解决问题。