微服務的概述
- 什么是微服務?
現今微服務界沒有一個統一的、標准的定義
微服務化的核心就是將統一的一站式應用,根據業務拆分成一個一個的服務,徹底的去耦合,每一個微服務提供單個業務功能的服務,一個服務做一件事, 從技術角度看就是一種小而獨立的處理過程,類似進程概念,能夠自行單獨啟動 或銷毀,擁有自己獨立的數據庫
- 微服務的架構
微服務架構是一種架構模式,它提倡將單一應用程序划分成一組小的服務,服務之間互相協調、互相配合,為用戶提供最終價值.每個服務運行在其獨立的進程中,服務與服務間采用輕量級的通信機制互相協作(通常是基於HTTP協議的RESTful API).每個服務都圍繞着具體業務進行構建,並且能夠被獨立的部署到生產環境、生產環境等.另外,應當盡量避免統一的、集中式的服務管理機制,對具體的一個服務而言,應根據業務上下文,選擇合適的語言、工具對其進行構建.
有哪些優點?
- 每個服務足夠內聚,足夠小,代碼容易理解這樣能聚焦一個指定的業務功能或業務需求
- 開發簡單、開發效率提高,一個服務可能就是專一的只干一件事.
-
微服務是松耦合的,是有功能意義的服務,無論是在開發階段或部署階段都是獨立的.
-
微服務能試用不同的語言開發
-
易於和第三方集成,微服務允許容易且靈活的方式集成自動部署,通過持續集成工具,如Jenkins,Hudson
-
微服務易於被一個開發人員理解,修改和維護,這樣小團隊能夠更關注自己的工作成果.無需通過合作才能體現價值
- 微服務允許你利用融合最新技術
微服務只是業務邏輯的代碼,不會和HTML,CSS或其他界面組件混合.
每個微服務都有自己的存儲能力,可以有自己的數據庫.也可以有統一的數據庫
有哪些缺點:
-
開發人員要處理分布式系統的復雜性
-
多服務運維難度,隨着服務的增加,運維的壓力也在增大
-
系統部署依賴
-
服務間通信成本
-
數據一致性
-
系統集成測試
-
性能監控
SpringBoot和SpringCloud那點事?
SpringBoot專注於快速方便的開發單個個體微服務。
SpringCloud是關注於全局微服務協調治理框架,他將Springboot開發的一個個單體微服務整合並管理起來,為各個微服務質檢提供配置管理,服務發現,斷路器,路由,微代理,事件總線,全局鎖,決策競選,分布式會話等集成服務。
Springboot可以離開SpringCloud單獨的使用開發項目,但是SpringCloud不能離開Springboot,屬於依賴的關系。
Springboot專注於快速、方便的開發單個微服務個體。
SpringCloud關注全局的服務治理框架。
SpringCloud中文網:https://springcloud.cc/
參考資料:https://www.springcloud.cc/spring-cloud-netflix.html
使用springcloud做一個簡單的查詢操作搭建項目的開發環境:
- 創建一個普通的maven工程(不用勾選任何選項),此時創建的是一個父工程
(以上創建一個普通的maven工程如果有哪里不清晰,可以查看MyBatis入門的第一天,里面有講解:https://www.cnblogs.com/LBJLAKERS/p/11324234.html)
在pom.xml文件夾中更改他的打包的方式,添加一句。
項目的打包類型:pom、jar、war
packing默認是jar類型,
<packaging>pom</packaging> ---------> 父類型都為pom類型
<packaging>jar</packaging> ---------> 內部調用或者是作服務使用
<packaging>war</packaging> ---------> 需要部署的項目
<packaging>pom</packaging>
在創建一個子工程,創建方式,如圖:(名稱為:zhservicecloud-common)
在父工程下創建一個子工程的方式:
- 使用同樣的方式分別創建子工程:txservicecloud-provider-dept-8001、txservicecloud-consumer-dep-80.
- 在父工程中的pom.xml文件中導入坐標
1 <dependencyManagement> 2 <dependencies> 3 <dependency> 4 <groupId>org.springframework.cloud</groupId> 5 <artifactId>spring-cloud-dependencies</artifactId> 6 <version>Finchley.SR1</version> 7 <type>pom</type> 8 <scope>import</scope> 9 </dependency> 10 <dependency> 11 <groupId>org.springframework.boot</groupId> 12 <artifactId>spring-boot-dependencies</artifactId> 13 <version>2.0.1.RELEASE</version> 14 <type>pom</type> 15 <scope>import</scope> 16 </dependency> 17 <dependency> 18 <groupId>mysql</groupId> 19 <artifactId>mysql-connector-java</artifactId> 20 <version>5.0.4</version> 21 </dependency> 22 <dependency> 23 <groupId>com.alibaba</groupId> 24 <artifactId>druid</artifactId> 25 <version>1.0.31</version> 26 </dependency> 27 <dependency> 28 <groupId>org.mybatis.spring.boot</groupId> 29 <artifactId>mybatis-spring-boot-starter</artifactId> 30 <version>1.3.0</version> 31 </dependency> 32 <dependency> 33 <groupId>ch.qos.logback</groupId> 34 <artifactId>logback-core</artifactId> 35 <version>1.2.3</version> 36 </dependency> 37 <dependency> 38 <groupId>junit</groupId> 39 <artifactId>junit</artifactId> 40 <version>${junit.version}</version> 41 <scope>test</scope> 42 </dependency> 43 <dependency> 44 <groupId>log4j</groupId> 45 <artifactId>log4j</artifactId> 46 <version>${log4j.version}</version> 47 </dependency> 48 </dependencies> 49 </dependencyManagement>
- 在MySQL的數據庫中創建一個dept的表結構,並插入數據:
1 DROP DATABASE IF EXISTS cloudDB01; 2 CREATE DATABASE cloudDB01 CHARACTER SET UTF8; 3 USE cloudDB01; 4 CREATE TABLE dept 5 ( 6 deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, 7 dname VARCHAR(60), 8 db_source VARCHAR(60) 9 ); 10 INSERT INTO dept(dname,db_source) VALUES('開發部',DATABASE()); 11 INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE()); 12 INSERT INTO dept(dname,db_source) VALUES('財務部',DATABASE()); 13 INSERT INTO dept(dname,db_source) VALUES('市場部',DATABASE()); 14 INSERT INTO dept(dname,db_source) VALUES('運維部',DATABASE()); 15 16 SELECT * FROM dept;
- 創建一個applicatioon.xml文件。用來配置數據庫的基本配置
1 server: 2 port: 8001 3 mybatis: 4 config-location: classpath:mybatis/mybatis.cfg.xml #mybatis配置文件所在路徑 5 type-aliases-package: zh.stu.service.model #所有Entity別名類所在包 6 mapper-locations: 7 - classpath:mybatis/mapper/**/*.xml #mapper映射文件 8 spring: 9 application: 10 name: zhservicecloud-dept 11 datasource: 12 type: com.alibaba.druid.pool.DruidDataSource #當前數據源操作類型 13 driver-class-name: com.mysql.jdbc.Driver #mysql驅動包 14 url: jdbc:mysql://localhost:3306/cloudDB01 #數據庫名稱 15 username: root 16 password: zhanghao22333 17 dbcp2: 18 min-idle: 5 #數據庫連接池的最小維持連接數 19 initial-size: 5 #初始化連接數 20 max-total: 5 #最大連接數 21 max-wait-millis: 200 #等待連接獲取的最大超時時間
- 因為在applicatioon.xml文件中mybatis.cfg.xml的文件配置,所以在創建一個此文件即可
- 創建一個部門的model,並要實現序列化的接口
1 public class Dep implements Serializable{ 2 private Long deptno; // 主鍵 3 private String dname; // 部門名稱 4 private String db_source;// 來自那個數據庫,因為微服務架構可以一個服務對應一個數據庫,同一個信息被存儲到不同數據庫 5 6 public Long getDeptno() { 7 return deptno; 8 } 9 10 public void setDeptno(Long deptno) { 11 this.deptno = deptno; 12 } 13 14 public String getDname() { 15 return dname; 16 } 17 18 public void setDname(String dname) { 19 this.dname = dname; 20 } 21 22 public String getDb_source() { 23 return db_source; 24 } 25 26 public void setDb_source(String db_source) { 27 this.db_source = db_source; 28 } 29 }
- 其中創建的子工程txservicecloud-provider-dept-8001,是服務的提供者。在他的pom.xml文件中導入坐標
1 <dependencies> 2 <dependency> 3 <groupId>junit</groupId> 4 <artifactId>junit</artifactId> 5 </dependency> 6 <dependency> 7 <groupId>mysql</groupId> 8 <artifactId>mysql-connector-java</artifactId> 9 </dependency> 10 <dependency> 11 <groupId>com.alibaba</groupId> 12 <artifactId>druid</artifactId> 13 </dependency> 14 <dependency> 15 <groupId>ch.qos.logback</groupId> 16 <artifactId>logback-core</artifactId> 17 </dependency> 18 <dependency> 19 <groupId>org.mybatis.spring.boot</groupId> 20 <artifactId>mybatis-spring-boot-starter</artifactId> 21 </dependency> 22 <dependency> 23 <groupId>org.springframework.boot</groupId> 24 <artifactId>spring-boot-starter-jetty</artifactId> 25 </dependency> 26 <dependency> 27 <groupId>org.springframework.boot</groupId> 28 <artifactId>spring-boot-starter-web</artifactId> 29 </dependency> 30 <dependency> 31 <groupId>org.springframework.boot</groupId> 32 <artifactId>spring-boot-starter-test</artifactId> 33 </dependency> 34 <!-- 修改后立即生效,熱部署 --> 35 <dependency> 36 <groupId>org.springframework</groupId> 37 <artifactId>springloaded</artifactId> 38 </dependency> 39 <dependency> 40 <groupId>org.springframework.boot</groupId> 41 <artifactId>spring-boot-devtools</artifactId> 42 </dependency> 43 <dependency> 44 <groupId>cn.tx.springcloud1</groupId> 45 <artifactId>txservicecloud-common</artifactId> 46 <version>1.0-SNAPSHOT</version> 47 </dependency> 48 </dependencies>
-
在provider的工程下創建一個deptdao的接口。
1 package zh.stu.dao; 2 3 import org.apache.ibatis.annotations.Mapper; 4 import zh.stu.service.model.Dept; 5 6 import java.util.List; 7 8 @Mapper 9 public interface DeptDao { 10 11 boolean addDept (Dept dept); 12 13 Dept findById(Long id); 14 15 List<Dept> findAll(); 16 }
-
創建一個service接口:DeptService
1 package zh.stu.service; 2 3 import org.springframework.transaction.annotation.Transactional; 4 import zh.stu.service.model.Dept; 5 6 import java.util.List; 7 8 @Transactional 9 public interface DeptService { 10 // 添加數據 11 boolean addDept (Dept dept); 12 // 根據條件查詢 13 Dept findById(Long id); 14 // 查詢數據庫表中的所有數據 15 List<Dept> findAll(); 16 }
- 在resource目錄下創建一個mapper.xml文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="zh.stu.dao.DeptDao"> 6 <select id="findById" resultType="dept" parameterType="Long"> 7 SELECT d.deptno,d.dname,d.db_source FROM dept d WHERE d.deptno=#{deptno} 8 </select> 9 <select id="findAll" resultType="dept"> 10 SELECT d.deptno,d.dname,d.db_source FROM dept d 11 </select> 12 <insert id="addDept" parameterType="dept"> 13 INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE()); 14 </insert> 15 </mapper>
-
實現該service接口
1 package zh.stu.service.ServiceImpl; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 import zh.stu.dao.DeptDao; 6 import zh.stu.service.DeptService; 7 import zh.stu.service.model.Dept; 8 9 import java.util.List; 10 11 @Service 12 public class DeptServiceImpl implements DeptService { 13 14 @Autowired 15 private DeptDao deptDao; 16 17 @Override 18 public boolean addDept(Dept dept) { 19 return deptDao.addDept(dept); 20 } 21 22 @Override 23 public Dept findById(Long id) { 24 return deptDao.findById(id); 25 } 26 27 @Override 28 public List<Dept> findAll() { 29 return deptDao.findAll(); 30 } 31 }
-
創建一個controller
1 package zh.stu.controller; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.web.bind.annotation.*; 5 import zh.stu.service.DeptService; 6 import zh.stu.service.model.Dept; 7 8 import java.util.List; 9 10 @RestController 11 public class DeptController { 12 13 @Autowired 14 private DeptService deptService; 15 16 @RequestMapping(value = "/dept/add",method = RequestMethod.POST) 17 public boolean add(@RequestBody Dept dept) 18 { 19 return deptService.addDept(dept); 20 } 21 22 @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET) 23 public Dept dept (@PathVariable("id") Long id){ 24 return deptService.findById(id); 25 } 26 27 @RequestMapping(value = "/dept/list",method = RequestMethod.GET) 28 public List<Dept> dept() 29 { 30 return deptService.findAll(); 31 } 32 }
- 添加一個SpringApplicationTx類,運行此類,在控制台輸入控制器中添加的路徑:http://localhost:8001/dept/list
1 package zh.stu; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 @SpringBootApplication 7 public class SpringApplicationTx { 8 public static void main(String[] args) { 9 SpringApplication.run(SpringApplicationTx.class,args); 10 } 11 }
結果:
附一張項目結構圖
- 以上是服務的提供端
- 在consumer和provider之間的的調用,在consummer端對provider的調用
- 同樣是在resource的目錄下新添加一個application.xml的文件:制定端口號80
server: port: 80
- 在新加一個RestConfigBean的類,將RestTemplate交給容器
1 package zh.stu; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.web.client.RestTemplate; 6 7 @Configuration 8 public class RestConfigBean { 9 @Bean 10 public RestTemplate restTemplate() { 11 return new RestTemplate(); 12 } 13 }
- 添加控制器,對兩不同條件的查詢做測試
1 package zh.stu.controller; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.web.bind.annotation.PathVariable; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RestController; 7 import org.springframework.web.client.RestTemplate; 8 import zh.stu.service.model.Dept; 9 10 import java.util.List; 11 12 @RestController 13 public class DeptController { 14 15 private String REST_URL_PREFIX="http://localhost:8001/"; 16 17 @Autowired 18 private RestTemplate restTemplate; 19 20 @RequestMapping("/consumer/dept/getdept/{id}") 21 public Dept getDept(@PathVariable("id") Long id){ 22 return restTemplate.getForObject(REST_URL_PREFIX+"dept/get/"+id,Dept.class); 23 } 24 25 @RequestMapping("/consumer/dept/findall") 26 public List<Dept> findAll(){ 27 return restTemplate.getForObject(REST_URL_PREFIX+"dept/list",List.class); 28 } 29 }
- 創建SpringAppConsumerTx類文件
1 package zh.stu; 2 3 4 import org.springframework.boot.SpringApplication; 5 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 7 @SpringBootApplication 8 public class SpringAppConsumerTx { 9 public static void main(String[] args) { 10 SpringApplication.run(SpringAppConsumerTx.class,args); 11 } 12 }
啟動之后在地址欄根據在控制器中添加的路徑輸地址,可查詢出相應的數據。
注意:在啟動consumer端的SpringAppConsumerTx之前,就應該把provider端啟動起來,因為在consumer端要訪問provider。