微服務 Spring Cloud

Spring Cloud -- 微服務初探及實作

雅各 2021/06/10 10:54:50
42

前言

     微服務架構(Microservice Architecture)最早在2014年由Martin Fowler (https://martinfowler.com/articles/microservices.html)提出,他指出:微服務架構是一種架構模式,或著說是一種架構風格,他提倡將單一應用程序劃分成一組小的服務,每個服務運行在其獨立、自身的程序中,服務之間互相協調,互相配合,為用戶提供最終價值。服務之間採輕量級的通信機制互相溝通(通常基於HTTP的RESTful API)。每個微服務都圍繞著具體的業務進行建構,並且能夠被獨立地部屬到生產環境。另外,應盡量避免統一的、集中式的服務管理機制,對具體的一個服務而言,應該根據業務的上下游資料,選擇合適的語言及工具進行構建,以一個非常輕量級的集中式管理來協調這些服務,可以使用不同的語言來編寫服務,也可以使用不同的數據存取。

     因此,微服務化的核心,就是將傳統的一站式應用,根據業務拆分成一個一個的服務,徹底地將每個服務去耦合,每個微服務提供單個業務功能服務,一個服務做一件事,能夠自行單獨啟動或銷毀,並擁有自己的資料庫

     接下來會在文章中跟大家分享,如何使用Spring cloud建立一個簡易的微服務架構。

Spring cloud是什麼?

     Spring cloud是基於Spring Boot提供的一套微服務解決方案,他為開發人員提供了許多工具,達到快速構建分布式系統中的一些常見模式其內容較常用的有服務註冊與發現、配置管理、服務熔斷器、全鍊路監控、服務網關、負載均衡等組件,它們都可以利用Spring Boot的開發風格做到一鍵部屬或啟動,是一套讓開發者感到簡單易懂、易部屬及易維護的分布式系統開發套件。

為什麼要用Spring cloud?

     Spring cloud擁有完整的微服務框架所需要的工具,支持Rest、多語言、高可用及高容錯性、容易學習,已成為許多大公司愛用的架構。

開始建立Spring Cloud整體父工程project

     接下來,我們開始建立第一個Spring Cloud的父工程project吧~

     本範例會帶大家建立一個整體的父工程project、一個共用的API服務、一個Service端微服務及一個Client端微服務,來模擬客戶端的介面操作增刪改查,去打服務端的API,所使用的環境為Java 8、MySQL Router 8.0,所需要的背景知識為Spring boot、mybatis、MVC架構等等。

     

     1.首先,開啟Eclipse,右鍵 New -> Other...

    

    2.選擇Mavan -> Mavan Project (建立父工程使用Mavan Project,微服務建立使用Mavan Module) -> 按 Next >

 

    3.這邊先勾選Create a simple project

 

    4.填上Group Id、Artifact Id、Packaging選擇pom

 

    5.完成父工程的構建,會看到有一個src的資料夾及一個pom.xml文件

 

    6.再來我們要添加所需要用到的jar到pom.xml,配置如下

    以下為目前配置過可以使用的spring cloud的版本,每種Spring boot的版本都有相對應的spring cloud版本做搭配,搭配錯誤會無法啟動

    本範例是用spring boot 2.2.2 Release 及spring cloud Hoxton.SR1做搭配

    詳細文件在spring的官網可以查到 (https://spring.io/projects/spring-cloud)

<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>
	<groupId>com.jacob.springcloud</groupId>
	<artifactId>microservicecloud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<junit.version>4.12</junit.version>
		<log4j.version>1.2.17</log4j.version>
		<lombok.version>1.16.18</lombok.version>
		<slf4j.version>1.7.30</slf4j.version>
		<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
		<spring-boot.version>2.2.2.RELEASE</spring-boot.version>
	</properties>

	<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>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-dependencies</artifactId>
				<version>${spring-boot.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
				<version>5.1.44</version>
			</dependency>
			<dependency>
				<groupId>com.alibaba</groupId>
				<artifactId>druid</artifactId>
				<version>1.0.31</version>
			</dependency>
			<dependency>
				<groupId>org.mybatis.spring.boot</groupId>
				<artifactId>mybatis-spring-boot-starter</artifactId>
				<version>1.3.2</version>
			</dependency>
			<dependency>
				<groupId>ch.qos.logback</groupId>
				<artifactId>logback-classic</artifactId>
				<version>1.2.3</version>
				<scope>test</scope>
			</dependency>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>${junit.version}</version>
				<scope>test</scope>
			</dependency>
			<dependency>
				<groupId>log4j</groupId>
				<artifactId>log4j</artifactId>
				<version>${log4j.version}</version>
			</dependency>
			<dependency>
				<groupId>org.slf4j</groupId>
				<artifactId>slf4j-api</artifactId>
				<version>${slf4j.version}</version>
			</dependency>
			<dependency>
				<groupId>org.slf4j</groupId>
				<artifactId>slf4j-simple</artifactId>
				<version>${slf4j.version}</version>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<build>
		<finalName>microservicecloud</finalName>
		<resources>
			<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<configuration>
					<delimiters>
						<delimit>$</delimit>
					</delimiters>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

 

    到此,父工程建立完成。

 

建立Spring Cloud Microservicecloud-API

    接下來,要建立微服務的一些共用的API服務

    1.在父工程上右鍵 -> New -> Other...

 

    2.選擇 Mavan -> Mavan module 後按 Next >

 

    3.勾選Create a simple project,Module Name取名後按 Next >

    

    4.Packaging選擇jar後,按Finish

 

    5.完成建立共用的API服務

 

    6.這時進到父工程的pom.xml,應可看到下方出現了子工程的modules

<modules>
		<module>microservicecloud-api</module>
</modules>

 

    7.進到microservicecloud-api中,可看到JRE也是直接繼承JavaSE-1.8

 

    8.附上microservicecloud-api中 pom.xml設定

<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>com.jacob.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>microservicecloud-api</artifactId> <!-- 當前Module我自己叫什麼名字 -->
	<dependencies> <!-- 當前Module所需用的jar包,若在父類別中已有定義則不需再寫版本號 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.0</version>
            <scope>provided</scope>
		</dependency>		
	</dependencies>
</project>

 

    9.再來我們建立一個模擬部門的Entity,右鍵 -> New -> package,取package名稱

 

    10.在package中建立一個class Dept.java

package com.jacob.springcloud.entities;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@SuppressWarnings("serial")
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class Dept implements Serializable{ // Dept(Entity) orm 在mysql中也有一個Dept(table) 為類表關係映射 //必須序列化

	private Long deptno; //主鍵
	private String dname; //部門名稱 
	private String db_source; //來自那個資料庫,因為微服務架構可以一個服務對應一個資料庫,同一個信息被儲存到不同資料庫

}

 

    11.建完之後,回到microservicecloud-api在local端生成最新的jar包 右鍵 -> Run as -> Mavan clean

 

    12.右鍵 -> Run as -> Mavan install

 

    13.成功畫面如下

 

    14.這樣未來後續其他微服務若想使用該API,直接在pom.xml調用即可,不需再自行新增~

<groupId>com.jacob.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>

 

建立Spring Cloud 微服務Service端

    接下來來建立在這個微服務中提供服務的Service端~

    1.在父工程上右鍵 -> New -> Other...

 

    2.選擇 Mavan -> Mavan module 後按 Next >

 

    3.勾選Create a simple project,Module Name取名後按 Next >

 

    4.Packaging選擇jar後,按Finish

 

    5.完成建立Service端微服務包

 

    6.回到父工程的pom.xml,可以發現modules多增加一個Service端的服務繼承了父工程

 

    7.針對Service端的服務建置pom.xml,提供配置如下

<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>com.jacob.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>microservicecloud-provider-dept-8001</artifactId>
	<dependencies>
	
		<dependency><!-- 自己定義的api通用包 -->
			<groupId>com.jacob.springcloud</groupId>
			<artifactId>microservicecloud-api</artifactId>
			<version>${project.version}</version>
		</dependency>
		
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jetty</artifactId>
		</dependency>
		<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>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>springloaded</artifactId>
			<version>1.2.8.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
		</dependency>
	</dependencies>
</project>

 

    8.再來在src/main/recouse在src/main/resources 中,建立application建立application.yml,配置如下

server:
  port: 8001
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml     #mybatis配置文件所在路徑
  type-aliases-package: com.jacob.springcloud.entities   #所有Entity別名類所在package
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml                    #mapper映射文件
  
spring:
  application:
    name: microservicecloud-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource         #當前資料源操作類型
    driver-class-name: org.gjt.mm.mysql.Driver           #mysql驅動包
    url: jdbc:mysql://localhost:3306/cloudDB01?useSSL=false #資料庫名稱,請自訂
    username: xxxx #資料庫帳號,請自訂
    password: 1111 #資料庫密碼,請自訂
    dbcp2:
      min-idle: 5                                        #資料庫連接池的最小維持連接數
      initial-size: 5                                    #初始化連接數
      max-idle: 5                                        #最大連接數
      max-wait-millis: 200                               #等待連接獲取最大超時時間

 

     在此使用mybatis來做資料庫的操作,因為主題為微服務,在此僅提供建立的文件,不探討mybatis的原理

     9.在resources中建立一個mybatis folder,裡面放mybatis.cfg.xml文件,內容如下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>

	<settings>
		<setting name="cacheEnabled" value="true"/><!-- 二級緩存開啟-->
	</settings>

</configuration>

 

    10.再來我們建立一些DB的資料

create database cloudDB01 character set utf8;
use cloudDB01;
create table dept
(
	deptno bigint not null primary key auto_increment,
	dname varchar(60),
	db_source varchar(60)
);

insert into dept(dname, db_source) values('開發部',database());
insert into dept(dname, db_source) values('人事部',database());
insert into dept(dname, db_source) values('財務部',database());
insert into dept(dname, db_source) values('市場部',database());
insert into dept(dname, db_source) values('維運部',database());

select *
from dept

 

    資料狀況如下

 

    11.回到Service端微服務,建立一個dao層的 package ,並建立簡易的增刪改查功能

package com.jacob.springcloud.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.jacob.springcloud.entities.Dept;

@Mapper
public interface DeptDao {

	public boolean addDept(Dept dept);
	public Dept findById(Long id);
	public List<Dept> findAll();
	
}

 

    12.在resources/mybatis 中建一個mapper folder,再建立一個DeptMapper.xml,內容如下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jacob.springcloud.dao.DeptDao">

	<select id="findById" resultType="Dept" parameterType="Long">
		select deptno,dname,db_source from dept where deptno=#{deptno};
	</select>
	<select id="findAll" resultType="Dept">
		select deptno,dname,db_source from dept;
	</select>
	<insert id="addDept" parameterType="Dept">
		INSERT INTO dept(dname, db_source) VALUES(#{dname}, DATABASE());
	</insert>

</mapper>

 

    目前建立完應該是這樣

 

    13.建立service層 package及程式,程式如下

package com.jacob.springcloud.service;

import java.util.List;

import com.jacob.springcloud.entities.Dept;

public interface DeptService {
	public boolean add(Dept dept);
	public Dept get(Long id);
	public List<Dept> list();
}

 

    14.建立實現service的impl package及程式,程式如下

package com.jacob.springcloud.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jacob.springcloud.dao.DeptDao;
import com.jacob.springcloud.entities.Dept;
import com.jacob.springcloud.service.DeptService;

@Service
public class DeptServiceImpl implements DeptService {
	
	@Autowired
	private DeptDao dao;

	@Override
	public boolean add(Dept dept) {
		return dao.addDept(dept);
	}

	@Override
	public Dept get(Long id) {
		return dao.findById(id);
	}

	@Override
	public List<Dept> list() {
		return dao.findAll();
	}

}

 

    15.最後完成controller層的package及增刪改查API,如下

package com.jacob.springcloud.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.jacob.springcloud.entities.Dept;
import com.jacob.springcloud.service.DeptService;

@RestController
public class DeptController {

	@Autowired
	private DeptService service;
	
	
	@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
	public boolean add(@RequestBody Dept dept) {
		return service.add(dept);
	}
	
	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	public Dept get(@PathVariable("id") Long id) {
		return service.get(id);
	}
	
	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
	public List<Dept> list() {
		return service.list();
	}
	
}

 

    16.MVC完成後,在com.jacob.springcloud下建立一個主啟動程式,如下

package com.jacob.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DeptProvider8001_App {

	public static void main(String[] args) {
		SpringApplication.run(DeptProvider8001_App.class, args);
	}

}

 

    完成後的package如下

 

    17.在DeptProvider8001_App上 右鍵 -> Run As -> Spring Boot App 

 

    成功啟動,會看到如下顯示

 

    18.上述文件建立完成無誤後,可啟動,並至瀏覽器上輸入http://localhost:8001/dept/list,可成功查詢到DB的資料,Service端建立完成

 

    建立Spring Cloud 微服務Client端

    接下來來建立在這個微服務中提供服務的Client端~

    1.請先按照上面建立Service端微服務的1~5的步驟建立一個Client端的微服務,建立完如下圖顯示

 

    2.建立pom.xml,配置如下

<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>com.jacob.springcloud</groupId>
		<artifactId>microservicecloud</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>microservicecloud-consumer-dept-80</artifactId>
	<description>部門微服務消費者</description>
	
	<dependencies>
		<dependency><!-- 自己定義的api -->
			<groupId>com.jacob.springcloud</groupId>
			<artifactId>microservicecloud-api</artifactId>
			<version>${project.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<!-- 修改後立即生效,熱部署 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>springloaded</artifactId>
			<version>1.2.8.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
		</dependency>
	</dependencies>
</project>

 

    3.建立application.yml檔於resources中,配置如下

server:
  port: 80

 

    4.建立ConfigBean配置文件於com.jacob.springcloud.cfgbeans的package下

package com.jacob.springcloud.cfgbeans;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;


@Configuration
public class ConfigBean {//@Configuration + ConfigBean 等於applicationContext.xml文件

	@Bean
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}
	
}

 

    因為這部分為Client端,為消費者所使用的端口,故不應會有Service層,在此應用RestTemplate來做接口的調用

    RestTemplate提供了多種便捷訪問遠端Http服務的方法,是一種簡單便捷的訪問restful服務的class,為Spring提供用於訪問Rest服務的客戶端模板工具集。

    使用上非常簡單,它的方法postForObject共有三個參數->(url, requestMap, ResponseBean.class),分別代表->(Rest請求地址, 請求參數, Http響應轉換被轉 

    換的對象類型)、getForObject共有兩個參數->(url, ResponseBean.class),分別代表->(Rest請求地址, Http響應轉換被轉換的對象類型)

    5.建立Controller

package com.jacob.springcloud.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
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 com.jacob.springcloud.entities.Dept;

@RestController
public class DeptController_Consumer {

	private static final String REST_URL_PREFIX = "http://localhost:8001";
	
	@Autowired
	private RestTemplate restTemplate;
	
	@RequestMapping(value="/consumer/dept/add")
	public boolean add(Dept dept) {
		return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
	}
	
	@RequestMapping(value="/consumer/dept/get/{id}")
	public Dept get(@PathVariable("id") Long id) {
		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
	}
	
	@SuppressWarnings("unchecked")
	@RequestMapping(value="/consumer/dept/list")
	public List<Dept> list() {
		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
	}
	
}

 

   6.建立Client端主啟動類

package com.jacob.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DeptConsumer80_App {

	public static void main(String[] args) {
		SpringApplication.run(DeptConsumer80_App.class, args);
	}

}

 

    完成後Client端配置如下

    至此,我們已經完成了微服務的Service端及Client端的配置,現在我們來測試看看同時啟動的狀態,分別啟動microservicecloud-provider-dept-8001及microservicecloud-consumer-dept-80,我們使用Client端的Controller方法來看看是否能打到Service端提供的增刪改查服務API

    1.開啟瀏覽器,輸入"localhost/consumer/dept/get/2",可看到能順利查到id為2的那筆資料

    2.輸入"localhost/consumer/dept/list",可查到所有資料

 

    3.輸入"localhost/consumer/dept/add?dname=大數據",頁面顯示true,表示資料已成功insert進入DB中,使用localhost/consumer/dept/list可查到,如下圖

 

以上,我們成功建立了一個模擬的Service端及Client端的微服務,未來將繼續跟大家分享Spring Cloud的其他工具,若其中有疏漏,也歡迎各位前輩不吝指教,謝謝大家~

 

參考文獻

    https://spring.io/projects/spring-cloud

    https://martinfowler.com/articles/microservices.html

    急速開發JAVA大系統 Spring Boot 又輕又快又好學

    尚硅谷Spring Cloud教程

雅各