SpringCloud 回顾cap原则这里是引用
RDBMS :Mysql Oracle sqlserver ==ACID
NoSQL:redis mongdb ==CAP
ACID是什么- A (Atomictity) 原子性
- C (Consistency) 一致性
- I (Isolation) 隔离性
- D (Durability) 持久性
-
C (Consistency) 强一致性
-
A (Availability) 可用性
-
P (Partition tolerance) 分区容错性
CAP 的三进二:CA AP CP
CAP理论的核心
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
CA without P:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但其实分区不是你想不想的问题,而是始终会存在,因此CA的系统更多的是允许分区后各子系统依然保持CA。
CP without A:如果不要求A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
AP wihtout C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。
Zookeeper保证的是CP
Eureka保证的是AP
SpringCloud是什么自己的理解:
SpringCloud 是建立在SpringBoot之上的多个微服务结构
他的目的是通过分布式服务(通过网络搭建服务平台,将各个服务区进行相连,并且数据相同,俗称云端)来进行发现注册,配置中心,负载均衡,等一系列操作
注册中心 操作:建立一个空的工程,在工程中,导包
4.0.0 org.example SpringCloud1.0-SNAPSHOT SpringCloud-api SpringCloud-provider-dept-8001 SpringCloud-consumer-dept-80 SpringCloud-Eureka-7001 SpringCloud-Eureka-7002 SpringCloud-Eureka-7003 pom UTF-8 1.8 1.8 4.12 1.18.22 1.2.17 com.alibaba.cloud spring-cloud-alibaba-dependencies2021.1 pom import org.springframework.cloud spring-cloud-dependencies2021.0.1 pom import org.springframework.boot spring-boot-dependencies2.6.6 pom import mysql mysql-connector-java8.0.28 com.alibaba druid1.2.8 org.mybatis.spring.boot mybatis-spring-boot-starter2.2.2 junit junit${junit.version} org.projectlombok lombok${lombok.version} log4j log4j${log4j.version} ch.qos.logback logback-core1.2.11 org.slf4j slf4j-log4j122.0.0-alpha7 org.slf4j slf4j-reload4j2.0.0-alpha7
建立module
API实现访问的接口,我们需要拿到的数据都在里面
consumer 消费者,通过地址远程访问我们的数据
Euerka 注册中心,7001-7003 三个不同的注册中心,可以理解为三台地址不在同一个地方的服务器
provider 提供中心 7001-7003注册中心最后注册到的管理地址
API配置以及代码:
package com.study.springcloud.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@NoArgsConstructor
@Accessors(chain = true)//链式写法
public class Dept implements Serializable {//Dept实体类,orm mysql --dept 类表关系映射
private Long deptno;//主键
private String dename;
//这个数据是存在那个数据库的字段里面的 微服务 一个服务对应一个数据量,同一个信息可能存在不同的数据库
private String db_source;
public Dept(String dename) {
this.dename = dename;
}
}
消费者配置:
package com.study.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {//@Configuration spring applicationContext.xml
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
package com.study.springcloud.controller;
import com.study.springcloud.pojo.Dept;
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 java.util.List;
@RestController
public class DeptConsumerController {
//理解:消费者 不应该有service层
//支持restful风格 ResTemplate 供我们直接调用就可以了 注册到Spring中
//(url,实体:map class responseType)
@Autowired
private RestTemplate restTemplate; //提供多种远程便捷访问Http服务的方法 简单的restful服务模板
// http://localhost:8001/
private static final String REST_URL_PREFIX="http://localhost:8001";
@RequestMapping("/consumer/dept/add")
public Boolean add(Dept dept){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/add",Boolean.class,dept);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept queryById(@PathVariable("id") long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/list")
public List list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
}
package com.study.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
加一个80的端口号
7001-7003配置server:
port: 7001
#eureka配置
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #如果为false 表示自己为注册中心
service-url: # 监控页面~ 单机ttp://${eureka.instance.hostname}:${server.port}/eureka/
#集群(关联):
defaultZone: http://eureka7002.com:7002/eureka/,http://eu
7001-7003启动类 以此类推
package com.study.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //服务端的启动类,可以
public class EurekaServer_7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7002.class,args);
}
}
提供者:
package com.study.springcloud.controller;
import com.study.springcloud.pojo.Dept;
import com.study.springcloud.service.DeptService;
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.*;
import java.util.List;
//提供restful风格服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
//获取client配置信息 获取具体的微服务
@Autowired
private DiscoveryClient discoveryClient;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id){
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List queryAll(){
return deptService.queryAll();
}
//注册进来的微服务 获取一些消息
@RequestMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表的清单
List services = discoveryClient.getServices();
System.out.println("discovery=>services:"+services);
//得到一个具体的微服务清单 通过微服务的id application name
List instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"t"+
instance.getPort()+"t"+
instance.getUri()+"t"+
instance.getServiceId()
);
}
return this.discoveryClient;
}
}
package com.study.springcloud.dao;
import com.study.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List queryAll();
}
package com.study.springcloud.service;
import com.study.springcloud.pojo.Dept;
import org.springframework.stereotype.Service;
import java.util.List;
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List queryAll();
}
package com.study.springcloud.service;
import com.study.springcloud.dao.DeptDao;
import com.study.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryById(Long id) {
return deptDao.queryById(id);
}
@Override
public List queryAll() {
return deptDao.queryAll();
}
}
package com.study.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
//启动类
@SpringBootApplication
@EnableEurekaClient//自动在服务启动后 自动注册到eureka中
@EnableDiscoveryClient//服务发现
public class DeptProvider_8001 {
public static void main(String[] args) {
// //使用纯后台方式启动,不占用端口,springboot2.0以后的写法
// new SpringApplicationBuilder().sources(DeptProvider_8001.class).web(WebApplicationType.NONE).run(args);
//使用web方式启动,会占用端口
SpringApplication.run(DeptProvider_8001.class, args);
}
}
insert into dept (dname,db_source) values (#{dname},DATABASE()); select * from dept where deptno = #{deptno};
server:
port: 8001
# mybatis配置
mybatis:
type-aliases-package: com.study.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
# spring的配置
spring:
application:
name: SpringCloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver #数据源
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
#erueka 服务注册到哪里
#Eureka的配置,注册到哪里
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改erueka上的默认描述信息
#info配置
info:
app.name: Mrone-springcloud
company.name: blog.Mrone.com
Ribbon
Ribbon是客户端的均衡负载器。
第一首先要在提供端导入eureka的包以及ribbon的包
第二 在最新版本里,我们需要在eureka配置中加入 否则会识别不到注册地址[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
第三 在进行客户端操作时,由于版本问题,我们不再使用老版本操作
需要在夫工程中,添加以下依赖
org.springframework.cloud
spring-cloud-dependencies
Hoxton.SR1
pom
import
再在客户端中添加上eureka包
配置客户端eureka
将Ribbon开启在端口中只需要添加一个注解 @LoadBalanced
Ribbon在进行多提供者时 默认按顺序来进行访问,当然我们可以自定义进行,但是我们的版本问题,不能添加ribbon依赖,会报错。



