微服务的概述
- 什么是微服务?
现今微服务界没有一个统一的、标准的定义
微服务化的核心就是将统一的一站式应用,根据业务拆分成一个一个的服务,彻底的去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事, 从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动 或销毁,拥有自己独立的数据库
- 微服务的架构
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值.每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相协作(通常是基于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。