1. 微服务
1.1 架构体系演变过程
单体架构: 就是将所有的业务场景的表示层、业务逻辑层和数据,访问层放在一个工程中,最终经过编译、打包,部署在一台服务器上。。
垂直架构: 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率.
分布式架构: 表示把不同的层进行分开来管理,其实就是可以按照mvc架构,只不过把每个层变成一个单独的服务
SOA架构: 基于分布式架构的基础之上进行细粒化拆分的一种架构.
面向服务架构,其实就是把每个项目拆分成多个独立的服务,而每个服务中都一个独立的个体.
小结:
分布式架构和SOA架构目前比较流程的技术栈还是ssm或者ssh.
微服务架构:
微服务架构是一项在云中部署应用和服务的新技术,微服务可以在“自己的程序”中运行,并通过“轻量级设备与HTTP型API进行沟通.
简单来说:微服务,是在soa架构的基础之上进行再次的细粒化,达到“微”的程度,每个服务都是一个独立的个体服务,服务与服务之间耦合性比较小,而且微服务架构使用的技术栈必须是springboot为底层的技术栈,比如springcloud.
2. springcloud
概念:
springcloud是spring家族的一个产品,springcloud不是一个具体的技术,而是多个组件的集合,包含的组件常用的有:
eureka,fegin,ribbon,alibaba,gateway,bus,config等等.
springcloud版本号是以英国伦敦地铁站的名称来命名的。
springcloud和dubbo的对比分析
3. SpringCloud服务治理
3.1 Eureka的了解
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现。Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server,并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行
3.2 Eureka入门操作
3.2.1 不使用Eureka来完成服务之间的调用
思路:
- 创建一个provider服务,专门用来从数据库获取数据
- 创建一个consumer服务,去调用provider服务
provider服务部分:
1 导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2 创建实体
@Data
@AllArgsConstructor
public class Goods {
private int id;
private String title;//商品标题
private double price;//商品价格
private int count;//商品库存
}
3 编写dao
@Repository//注入到ioc容器
public class GoodsDao {
//单一查
public Goods findOne(int id){
return new Goods(1,"华为手机",3999,10000);
}
}
4 编写controller
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private GoodsDao goodsDao;
@GetMapping("/findOne/{id}")
public Goods findOne(@PathVariable Integer id){
return goodsDao.findOne(id);
}
}
5 启动入口类,访问服务 localhost:9091/provider/findOne/12
Consumer服务部分:
1 导包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2 实体类
@Data //lombok插件 提供setXxx,getXxx
@AllArgsConstructor //满参构造
@NoArgsConstructor //空参构造
public class Goods {
private int id;
private String title;//商品标题
private double price;//商品价格
private int count;//商品库存
}
3 编写RestTemplateConfig
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4 编写controller
/*
要去调用provider服务
*/
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
//根据商品id调用商品信息
@GetMapping("/findGoodsById/{id}")
public Goods findGoodsById(@PathVariable int id){
System.out.println("findGoodsById..."+id);
//1.调用provider服务中的接口
String url="http://localhost:9091/provider/findOne/"+id;
//2.利用restTemplate模板模拟浏览器发请求
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
5 测试访问consumer服务 localhost:9090/consumer/findGoodsById/12
总结:
RestTemplate是Spring用于同步client端的核心类,简化了与http服务的通信,并满足RestFul原则,程序代码可以给它提供URL,并提取结果,而且是比较优雅的http请求方式.
简单来说就是模拟了浏览器发出请求的方式。
3.2.2 使用Eureka来完成服务之间的调用
使用eureka的服务
1 导包,在parent工程中加入依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--spring cloud 版本-->
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<!--引入Spring Cloud 依赖-->
<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>
</dependencies>
</dependencyManagement>
2 在eureka-server服务中加入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
3 在入口类之上加入开启Eureka服务的注解
@SpringBootApplication
//加入开启euerka服务的注解
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class,args);
}
}
4 配置文件yml
server:
port: 8080
eureka:
instance: #实例
hostname: localhost # 主机名
client:
service-url:
# http://localhost:8080/eureka 这个地址是eureka服务端和客户端之间通信的接口地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#注册
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
#发现
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
application:
name: eureka_server
5 启动Eureka-server服务,localhost:8080
使用Eureka完善服务之间的调用
主要核心把provider和consumer这两个服务变成Eureka client服务
一 provider服务提供者部分
1 pom.xml导包
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2 在入口类之上可以加@EnableEurekaClient注解,新版springcloud也可以选择不加.
3 在配置文件配置关联EurekaServer信息.
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8080/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#如果不进行指定服务名称,则会显示unknown
spring:
application:
name: cloud-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
二 consumer服务消费者部分
1.pom.xml导包
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2 在入口类之上可以加@EnableEurekaClient注解,新版springcloud也可以选择不加
3 在配置文件配置关联EurekaServer信息
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8080/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#如果不进行指定服务名称,则会显示unknown
spring:
application:
name: cloud-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
三 服务消费者consumer远程调用服务生产者provider
在consumerController类中改造代码
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
//根据商品id调用商品信息
@GetMapping("/findGoodsById/{id}")
public Goods findGoodsById(@PathVariable int id){
System.out.println("findGoodsById..."+id);
//1.调用provider服务中的接口
/* String url="http://localhost:9091/provider/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);*/
//从eureka 服务列表中获取客户端服务列表,参数表示的是服务id
List<ServiceInstance> instanceList = discoveryClient.getInstances("CLOUD-PROVIDER1");
ServiceInstance serviceInstance = instanceList.get(0);
int port = serviceInstance.getPort();
String host = serviceInstance.getHost();
String instanceId = serviceInstance.getInstanceId();
System.out.println("port=|"+port+"| host=|"+host+"| instanceId=|"+instanceId);
String url="http://"+host+":"+port+"/provider/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
小结:
当我们的生产者服务要先注册到Eureka Server中,然后消费者服务才可以去Eureka Server中去 发现生产者服务.
Eureka两个功能:
1 第一个是注册中心
2 第二是远程调用
四 对Eureka配置进行操作
instance属性,写在client客户端服务中,控制的是Eureka服务列表中的服务.
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true
ip-address: 127.0.0.1
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}
client:
service-url:
defaultZone: http://localhost:8080/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
server属性,写在Eureka server服务中,控制的是Eureka注册中心的自我保护机制.
#表示Eureka自我保护机制
server:
enable-self-preservation: false #默认是true表示开启,false表示关闭
eviction-interval-timer-in-ms: 60000
3.2.3 Eureka集群高可用
实现步骤:
- 准备两个Eureka Server
- 分别进行配置,相互注册
- Eureka Client 分别注册到这两个 Eureka Server中
操作步骤:
1、导包
2、在入口类之上加入开启Eureka服务的注解@EnableEurekaServer
3、配置文件
eureka-server1模块中:
eureka:
instance: #实例
hostname: 127.0.0.1 # 主机名
client:
service-url:
# http://localhost:8080/eureka 这个地址是eureka服务端和客户端之间通信的接口地址
defaultZone: http://127.0.0.2:10080/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#注册
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
#发现
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
eureka-server模块中:
eureka:
instance: #实例
hostname: 127.0.0.2 # 主机名
client:
service-url:
# http://localhost:8080/eureka 这个地址是eureka服务端和客户端之间通信的接口地址
defaultZone: http://127.0.0.1:8080/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
#注册
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
#发现
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
生产者服务和消费者服务中注册或者发现两台Eureka-server
eureka:
instance:
hostname: 127.0.0.1 # 主机名
client:
service-url:
defaultZone: http://127.0.0.1:8080/eureka,http://127.0.0.2:10080/eureka
# eureka服务端地址,将来客户端使用该地址和eureka进行通信
以逗号间隔,
3.2 Consul
3.2.1 Consul的概述
Consul 是由 HashiCorp 基于 Go 语言开发的,支持多数据中心,分布式高可用的服务发布和注册服务软件。
• 用于实现分布式系统的服务发现与配置。
• 使用起来也较 为简单。具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署 。
启动命令: .\consul agent -dev
(dev模式:不会持久化数据)
3.2.2 Consul的入门案例
实现步骤:
- 搭建 Provider 和 Consumer 服务。
- 使用 RestTemplate 完成远程调用。
- 将Provider服务注册到Consul中。
- Consumer服务通过从 Consul 中抓取 Provider 地址完成远程调用。
一. Provider模块
- pom.xml
<dependencies>
<!--consul 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
- 配置文件application.yml
server:
port: 8000
spring:
cloud:
consul:
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: consul-provider # 应用名称
二. Consumer模块
1-pom.xml
<dependencies>
<!--consul 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2-配置文件application.yml
server:
port: 9000
spring:
cloud:
consul:
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: consul-consumer # 应用名称
3-Consumer控制层Controller
package com.cf.consul.controller;
import com.cf.consul.domain.Goods;
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("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
//演示discoveryClient 使用
List<ServiceInstance> instances = discoveryClient.getInstances("consul-PROVIDER");
//判断集合是否有数据
if(instances == null || instances.size() == 0){
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
System.out.println(host);
System.out.println(port);
String url = "http://"+host+":"+port+"/goods/findOne/"+id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
三. 测试
http://localhost:8500
3.3 Nacos
3.3.1 Nacos的概述
Nacos(Dynamic Naming and Configuration Service) 是阿里巴巴2018年7月开源的项目。
• 它专注于服务发现和配置管理领域 致力于帮助您发现、配置和管理微服务。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理。
• 一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心。
使用步骤:
双击startup.cmd或通过命令行方式 start “xx.cmd”
控制台账号,密码默认为:nacos
3.3.2 Nacos的入门案例
一. nacos-provider提供者模块
1-pom.xml
<dependencies>
<!--nacos-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2-application.yml
server:
port: 8000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
application:
name: nacos-provider # 服务名称
二. nacos consumer消费者模块
<dependencies>
<!--nacos-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2-application.yml
server:
port: 9000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
application:
name: nacos-consumer # 服务名称
三. 测试 http:localhost:8848/nacos