一:前提知识+相关说明
前提知识:springmvc+spring/springboot+mybatis+maven+git......
cloud技术的五大神兽:
面试题:
什么是微服务?
微服务之间如何独立通讯的?
SpringCloud和Dubbo有哪些区别?Dubbo:RPC SpringCloud:Restful
SpringBoot和SpringCloud,请谈谈对他们的理解?
什么是服务熔断?什么是服务降级?
微服务的优缺点分别是什么?说下你在项目开发中碰到的坑?
你所知道的微服务技术栈有哪些?请列举一二。
eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个的区别?说说ribbon,feign和nginx的区别?
二:微服务概述
1. 技术维度理解
微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或销毁,拥有自己独立的数据库。
单机系统(All In One):只有一个大的工程 -- war包
分布式系统:
各自模块/服务,各自独立出来,分灶吃饭 -- 拆分
各自微小的一个进程,让专业的人专业的模块,来做专业的事情 -- 各自独立的进程
独立部署 -- 拥有自己独立的数据库
2. 微服务
业界大牛马丁.福勒(Martin Fowler) 这样描述微服务:
论文网址: https://martinfowler.com/articles/microservices.html
强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题/提供落地对应服务的一个服务应用,狭意的看,可以看作Eclipse里面的一个个微服务工程/或者Module
3. 微服务架构
微服务架构是⼀种架构模式,它提倡将单⼀应⽤程序划分成⼀组⼩的服务,服务之间互相协调、互相配合,为⽤户提供最终价值。每个服务运⾏在其独⽴的进程中,服务与服务间采⽤轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进⾏构建,并且能够被独⽴的部署到⽣产环境、类⽣产环境等。另外,应当尽量避免统⼀的、集中式的服务管理机制,对具体的⼀个服务⽽⾔,应根据业务上下⽂,选择合适的语⾔、⼯具对其进⾏构建。
4. 微服务优缺点
优点:
每个服务足够内聚,足够小,代码容易理解这样能聚焦一个指定的业务功能或业务需求
开发简单、开发效率提高,一个服务可能就是专一的只干一件事
微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成
微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的
微服务能使用不同的语言开发
易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins,Hudson,bamboo
微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
微服务允许你利用融合最新技术
微服务只是业务逻辑的代码,不会和HTML,CSS或其它界面组件混合
每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库
缺点:
开发人员要处理分布式系统的复杂性
多服务运维难度,随着服务的增加,运维的压力也在增大
系统部署依赖
服务间通信成本
数据一致性
系统集成测试
性能监控......
5. 微服务技术栈有哪些
微服务技术栈:多种技术的集合体
微服务条目 | 落地技术 | 备注 |
---|---|---|
服务开发 | Springboot、Spring、SpringMVC | |
服务配置与管理 | Netflix公司的Archaius、阿里的Diamond等 | |
服务注册与发现 | Eureka、Consul、Zookeeper等 | |
服务调用 | Rest、RPC、gRPC | |
服务熔断器 | Hystrix、Envoy等 | |
负载均衡 | Ribbon、Nginx等 | |
服务接口调用(客户端调用服务的简化工具) | Feign等 | |
消息队列 | Kafka、RabbitMQ、ActiveMQ等 | |
服务配置中心管理 | SpringCloudConfig、Chef等 | |
服务路由(API网关) | Zuul等 | |
服务监控 | Zabbix、Nagios、Metrics、Spectator等 | |
全链路追踪 | Zipkin,Brave、Dapper等 | |
服务部署 | Docker、OpenStack、Kubernetes等 | |
数据流操作开发包 | SpringCloud Stream(封装与Redis,Rabbit、Kafka等发送接收消息) | |
事件消息总线 | Spring Cloud Bus | |
...... |
示例:
一个分布式的微服务架构 | 维度 | E时代下的数字生活 |
---|---|---|
服务治理 | 手机 | |
服务注册 | 电脑 | |
服务调用 | 路由器 | |
服务负载均衡 | 充电宝 | |
服务监控...... | 电器 | |
SpringCloud提供 | 小米科技提供 |
6. 为什么选择SpringCloud作为微服务架构
选型依据:整体解决方案和框架成熟度,社区热度,可维护性,学习曲线
当前各大IT公司用的微服务架构有哪些:阿里Dubbo/HSF;京东JSF;新浪微博Motan;Netflix/SpringCloud;
老系统用Dubbo多,新系统用SpringCloud多;
三:springcloud入门概述
1. 是什么
1.1 官网说明
SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。
SpringCloud利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等,它们都可以用SpringBoot的开发风格做到一键启动和部署。
SpringBoot并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
1.2 总结
SpringCloud=分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶。
1.3 SpringCloud与SpringBoot之间关系
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务。
SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖的关系.
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
1.4 SpringCloud与Dubbo的区别
互联网架构(分布式+服务治理Dubbo) 应用服务化拆分+消息中间件
对比:
社区活跃度:http://github.com/dubbo http://github.com/spring-cloud
Dubbo | SpringCloud | |
---|---|---|
服务注册中心 | Zookeeper | Spring Cloud Netflix Eureka |
服务调用方式 | RPC | Rest API |
服务监控 | Dubbo-monitor | Spring Boot Admin |
断路器 | 不完善 | Spring Cloud Netflix Hystrix |
服务网关 | 无 | Spring Cloud Netflix Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
消息总线 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
最大区别:SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。
2. 去哪下
官网:http://projects.spring.io/spring-cloud/
参考书:https://springcloud.cc/spring-cloud-netflix.html
API:https://springcloud.cc/spring-cloud-dalston.html
springcloud中国社区:http://springcloud.cn/
springcloud中文网:https://springcloud.cc/
四:Rest微服务构建案例工程模块
1.整体父工程MavenProject
1.新建父工程microservicecloud,切记是Packageing是pom模式
2.主要是定义POM文件,将后续各个子模块公用的jar包等统一提出来,类似一个抽象父类
<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>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.4</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.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</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>
</dependencies>
</dependencyManagement>
<modules>
</modules>
2.公共子模块MavenModule
1.新建microservicecloud-api -- 创建完成后请回到父工程查看pom文件变化
2.修改POM
3.新建部门Entity且配合lombok使用
4.mvn clean install后给其它模块引用,达到通用目的。也即需要用到部门实体的话,不用每个工程都定义一份,直接引用本模块即可。
1.xml文件
<dependencies><!-- 当前Module需要用到的jar包,按自己需求添加,如果父类已经包含了,可以不用写版本号 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
2.Dept实体
@NoArgsConstructor
//@AllArgsConstructor
@Data
@Accessors(chain=true)
public class Dept implements Serializable// entity --orm--- db_table 类表关系映射 //必须序列化
{
private Long deptno; // 主键
private String dname; // 部门名称
private String db_source;// 来自那个数据库,因为微服务架构可以一个服务对应一个数据库,同一个信息被存储到不同数据库
public Dept(String dname)
{
super();
this.dname = dname;
}
// public static void main(String[] args) {
// Dept dept = new Dept();
// dept.setDeptno(11L).setDname("jack").setDb_source("DB01");
// System.out.println(dept);
// }
}
3.部门微服务提供者Module
1.新建microservicecloud-provider-dept-8001 -- 创建完成后请回到父工程查看pom文件变化
2.POM
3.YML
4.工程src/main/resources目录下新建mybatis文件夹后新建mybatis.cfg.xml文件
5.MySQL创建部门数据库脚本
6.DeptDao部门接口
7.工程src/main/resources/mybatis目录下新建mapper文件夹后再建DeptMapper.xml
8.DeptService部门服务接口
9.DeptServiceImpl部门服务接口实现类
10.DeptController部门微服务提供者REST
11.DeptProvider8001_App主启动类
12.测试:http://localhost:8001/dept/get/2 http://localhost:8001/dept/list
2.POM
<!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</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</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
3.YML
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
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 # 数据库名称
username: root
password: root
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
4.新建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>
5.创建mysql脚本
DROP DATABASE IF EXISTS cloudDB01;
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;
6.新建DeptDao部门接口
@Mapper //@Mapper注解:注入springIOC容器,动态代理接口对象,可以用sql注解
public interface DeptDao{
public boolean addDept(Dept dept);
public Dept findById(Long id);
public List<Dept> findAll();
}
7.新建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.atguigu.springcloud.dao.DeptDao"> <!--命名空间=包名+接口名-->
<insert id="addDept" parameterType="Dept"> <!--id=方法名;parameterType=形参类型-->
insert into dept(dname,db_source) value(#{dname},database());
</insert>
<select id="findById" parameterType="Long" resultType="Dept"> <!--resultType=返回值类型-->
select deptno,dname,db_source from dept where deptno=#{deptno};
</select>
<select id="findAll" resultType="Dept">
select deptno,dname,db_source from dept;
</select>
</mapper>
8.DeptService部门服务接口
public interface DeptService{ //service接口上不需要注解
public boolean add(Dept dept); //方法名尽量与controller层restful风格统一
public Dept get(Long id);
public List<Dept> list();
}
9.DeptServiceImpl部门服务接口实现类
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
public boolean add(Dept dept){
return this.deptDao.addDept(dept);
}
public Dept get(Long id){
return this.deptDao.findById(id);
}
public List<Dept> list(){
return this.deptDao.findAll();
}
}
10.DeptController部门微服务提供者REST
@RestController //注入springIOC容器;将获取的数据以json字符串返回给前台
public class DeptController{
@Autowired
private DeptService deptService;
//POST|PUT提交:@RequestBody;GET提交:@RequestParam(获取请求头的数据)
@RequestMapping(value="/dept/add",method=RequestMethod.POST)
public boolean add(@RequestBody Dept dept){ //@RequestBody:获取请求体的数据
return this.deptService.add(dept);
}
@RequestMapping(value="/dept/get/{id}",method=RequestMethod.GET)
public Dept get(@PathVariable("id") Long id){ //PathVariable("id"):动态获取请求头中的参数
return this.deptService.get(id);
}
@RequestMapping(value="/dept/list",method=RequestMethod.GET)
public List<Dept> list(){
return this.deptService.list();
}
}
11.DeptProvider8001_App主启动类
@SpringBootApplication //主启动类
public class DeptProvider8001_App{
public static void main(String[] args){
SpringApplication.run(DeptProvider8001.class,args);
}
}
4.部门微服务消费者Module
1.新建microservicecloud-consumer-dept-80
2.POM
3.YML
4.com.atguigu.springcloud.cfgbeans包下ConfigBean的编写(类似spring里面的applicationContext.xml写入的注入Bean)
5.com.atguigu.springcloud.controller包下新建DeptController_Consumer部门微服务消费者REST
6.DeptConsumer80_App主启动类
7.测试
2.POM
<dependency><!-- 自己定义的api -->
<groupId>com.atguigu.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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
3.YML
server:
port: 81
4.cfgbeans包下新建ConfigBean
@Configuration //ConfigBean(@Configuration) --> applicationContext.xml
public class ConfigBean{
// <bean id="restTemplate" class="XXX.XXX.XXX.RestTemplate" />
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
5.新建DeptController_Consumer
@RestController //@Controller与@ResponseBody的结合
public class DeptController_Consumer{
private static final String REST_URL_PREFIX="http://localhost:8001";
/**
* 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
* ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
*/
@Autowired
private RestTemplate restTemplate;
//添加 Post提交 postForObject(url,requestMap,ResponseBean.class)
@RequestMapping(value="/consumer/dept/add")
public Boolean add(@ModelAttribute("dept") Dept dept){
return this.restTemplate.postForObject(REST_URL_PREFIX+"/dept/add", dept, Boolean.class);
}
//查询 Get提交 getForObject(url,ResponseBean.class)
@RequestMapping(value="/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return this.restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id, Dept.class);
}
//查询 Get提交 getForObject(url,ResponseBean.class)
@RequestMapping(value="/consumber/dept/list")
public List<Dept> list(){
return this.restTemplate.getForObject(REST_URL_PREFIX+"/depg/list", List.class);
}
}
6.DeptConsumer80_App主启动类
@SpringBootApplication //springboot启动类
public class DeptConsumer80_App{
public static void mian(String[] args){
SpringApplication.run(DeptConsumer80_App.class, args);
}
}