强一致性、弱一致性、最终一致性;

以bubbo来调用的
dubbo:阿里程序员,自创,一个技术,
zookeeper:注册中心功能
类似于我们的controller调用service,通过RPC去调用远程接口

注册中心,负载均衡器,网关,远程调用。
使用了spring cloud的组件,另外添加了三大组件:
1.Nacos
2.Sentinel
3.Seata

Maven 中央库搜索 Spring Cloud Dependencies,查看 Spring Cloud 版本;

Spring Boot 和 Spring Cloud 版本对应关系;

2020 版本变更

搭建一个spring cloud项目
目标:将之前写的spring boot项目拆解到spring cloud 项目中
一下市搭建分布式项目的步骤:
问题1:为什么要创建一个entity项目?
微服务之间涉及到跨模块的beanentity的调用,所以我首先将所有的分布式系统里的bean抽取出来,形成单独的模块,其他微服务以jar包的方式引入
问题2:微服务会不会跨服务调用 bean? 不会
举个栗子
其他模块会不会调用 账户模块 的user 对象? 会
对啊,既然会用到,那么我微服务 B 怎么去调用 微服务 A 里面的 bean?
问题3: 每个微服务就是一个项目? 是的
问题4: 是不是将每个微服务的 bean 抽取出来,形成一个单独的项目,其他微服务只要添加该项目依赖就可以引用到了
问题5: 那以后是不是还要把每一个service之类的都抽出来?
不用啊,我们通过resttemplate调用接口的方式实现微服务接口调用
在 Spring Cloud 项目中,每个微服务都可能用到的内容,比如 Entity、Util 等,我们将这些内容单独放到一个项目内,成为其余微服务的依赖;
1.创建骨架
创建 Java Maven 项目 java_spring_cloud_entity;





这时骨架就搭建好了,
2.导入依赖
- <dependency>
- <groupId>javax.servletgroupId>
- <artifactId>javax.servlet-apiartifactId>
- <version>4.0.1version>
- dependency>
-
- <dependency>
- <groupId>javax.persistencegroupId>
- <artifactId>javax.persistence-apiartifactId>
- <version>2.2version>
- dependency>
-
- <dependency>
- <groupId>com.fasterxml.jackson.coregroupId>
- <artifactId>jackson-coreartifactId>
- <version>${jackson.version}version>
- dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.coregroupId>
- <artifactId>jackson-databindartifactId>
- <version>${jackson.version}version>
- dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.coregroupId>
- <artifactId>jackson-annotationsartifactId>
- <version>${jackson.version}version>
- dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.datatypegroupId>
- <artifactId>jackson-datatype-jsr310artifactId>
- <version>${jackson.version}version>
- dependency>
-
- <dependency>
- <groupId>org.apache.commonsgroupId>
- <artifactId>commons-lang3artifactId>
- <version>3.12.0version>
- dependency>

2.11.3

3. 包装:将之前项目各个模块中 Entity 移植到该项目;
1.在基础包下创建与之前项目模块各个相同的包名

2.复制之前的entity过来放在对应的包中

3.复制过来后,需要修改entity中的引用路径

全部修改完后就,没错了,下一步打成jar包

4.打包jar


这里会出现问题情况:

这里是你的maven环境变量没有配置,步骤如下:





这样直接点确定,就好了,然后去测试,打开cmd

测试结果是正常这样后,就配好了,但是idea还没有感应到,重启idea,然后打开entity项目,重新输入打包命令


5.找到jar包,在target下面


这样就打好了,然后就可以把你的项目上传到远程仓库里面了
简介

Eureka Server(注册中心)




- # for server
- server.port=8760
- # for Eureka server
- eureka.instance.hostname=localhost
- eureka.client.registerWithEureka=false
- eureka.client.fetchRegistry=false
- eureka.client.servic
- @SpringBootApplication
- @EnableEurekaServer
- public class SpringCloudRegisterApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(SpringCloudRegisterApplication.class, args);
- }
-
- }






- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- dependency>
-
-
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- <version>5.1.47version>
- dependency>
-
-
- <dependency>
- <groupId>org.mybatis.spring.bootgroupId>
- <artifactId>mybatis-spring-boot-starterartifactId>
- <version>2.1.0version>
- dependency>
-
- <dependency>
- <groupId>com.github.pagehelpergroupId>
- <artifactId>pagehelper-spring-boot-starterartifactId>
- <version>1.4.1version>
- dependency>
-
-
- <dependency>
- <groupId>org.apache.commonsgroupId>
- <artifactId>commons-lang3artifactId>
- dependency>
-
-
- <dependency>
- <groupId>com.sfacgroupId>
- <artifactId>spring_cloudc_entityartifactId>
- <version>1.0-SNAPSHOTversion>
- dependency>
- #for server
- server.port=8761
-
- # for eureka client
- spring.application.name=client-test
- eureka.instance.hostname=localhost
- eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8760/eureka
- @SpringBootApplication
- @EnableDiscoveryClient
- public class SpringCloudTestApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(SpringCloudTestApplication.class, args);
- }
-
- }


访问微服务 client-test 接口:http://127.0.0.1:8761/api/contry/522






pom.xml:
-
-
-
org.springframework.boot -
spring-boot-starter-web -
-
-
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-client -
-
-
-
-
mysql -
mysql-connector-java -
5.1.47 -
-
-
-
-
org.mybatis.spring.boot -
mybatis-spring-boot-starter -
2.1.0 -
-
-
-
com.github.pagehelper -
pagehelper-spring-boot-starter -
1.4.1 -
-
-
-
-
org.apache.commons -
commons-lang3 -
-
-
-
-
com.sfac -
spring_cloudc_entity -
1.0-SNAPSHOT -
- #for server
- server.port=8763
-
- # for eureka client
- spring.application.name=client-account
- eureka.instance.hostname=localhost
- eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8760/eureka
-
- # for data source
- # mysql 5
- #spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test_city?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.username=root
- spring.datasource.password=123456
-
- # hikari pool
- spring.datasource.hikari.maximum-pool-size=20
- spring.datasource.hikari.minimum-idle=5
- spring.datasource.hikari.idle-timeout=180000
- spring.datasource.hikari.auto-commit=true
-
- # for mybatis
- mybatis.configuration.map-underscore-to-camel-case=true
启动类,添加 @EnableEurekaClient 注解;


这里如果出现了异常,找不到,执行mvn idea idea


1.1.1 需求
1.1.2 新建UserVo
- public class UserVo extends AbstractEntity {
- private static final long serialVersionUID = 1L;
- private String userName;
- private String email;
- private String password;
- private String userImage;
- private boolean rememberMe;
- private List
roles; -
- private City city;
- }
然后重新打包.......其他引用了entity微服务的地方就可以加载出userVo类。
1.1.3 消费者注册 RestTemplate;
可以新建一个包,也可以写再启动类中,注册成为bean
- @SpringBootApplication
- @EnableEurekaClient
- public class SpringCloudAccountApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(SpringCloudAccountApplication.class, args);
- }
-
-
- //消费者注册 RestTemplate;
- @Bean
- @LoadBalanced
- public RestTemplate restTemplate(){
- return new RestTemplate();
- }
- }
1.1.4实现 RestFul 接口
- //entity:上面写了,再entity微服务中
-
- //userDao:不需要写,只需要调用写好的即可。
-
- //userService:
-
- UserVo getUserVoByUserIDAndCityId(int userId,int CityId);
-
- //userServiceImpl:
-
- @Override
- public UserVo getUserVoByUserIDAndCityId(int userId, int CityId) {
- UserVo userVo = new UserVo();
- User user = userDao.getUserById(userId);
- BeanUtils.copyProperties(user,userVo); //copy
-
- //调用test微服务,获取城市信息
- City city = restTemplate.getForObject(
- "http://client-test/api/city/{cityId}", City.class, CityId);
- userVo.setCity(city);
- return userVo;
- }
-
- //userController:
-
- /**
- * 127.0.0.1/api/userVo/1/1890 ---- get
- */
- @GetMapping(value = "/userVo/{userId}/{cityId}")
- public UserVo getUserVo(@PathVariable int userId,@PathVariable int cityId) {
- return userService.getUserVoByUserIDAndCityId(userId,cityId);
- }
1.1.5 启动
1.启动项目,先调用注册中心,加载进去

2.调用接口:http://127.0.0.1:8762/api/userVo/1/1890

-
org.springframework.boot -
spring-boot-starter-security
- # for spring security
- # 高版本 spring cloud 舍掉该配置
- #spring.security.basic.enable=true
- spring.security.user.name=root
- spring.security.user.password=root
添加配置类 WebSecurityConfig.java
- @Configuration
- @EnableWebSecurity
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- // Basic 认证是一种较为简单的 HTTP 认证方式,客户端通过明文(Base64编码格式)传输用户名和密码到服务端进行认证
- http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
- http.csrf().disable();
- http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
- }
- } @Bean
- ReactorLoadBalancer
randomLoadBalancer( - Environment environment,
- LoadBalancerClientFactory loadBalancerClientFactory) {
- String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
- // 在此也可返回自定义负载均衡器
- return new RandomLoadBalancer(
- loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
- }
- # 关闭注册中心自我保护机制
- eureka.server.enable-self-preservation=false
- # 清理间隔
- eureka.server.eviction-interval-timer-in-ms=20000
- # 告诉服务端,如果我 10s 之内没有给你发心跳,就代表我死了,将我踢出掉,默认 90s
- eureka.instance.lease-expiration-duration-in-seconds=10
- # 每间隔 3s,向服务端发送一次心跳,证明自己依然存活,默认 30s
- eureka.instance.lease-renewal-interval-in-seconds=3



# for ribbon
client-test.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule


public class CustomLoadBalancerConfiguration {
@Bean
ReactorLoadBalancer randomLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
// 在此也可返回自定义负载均衡器
return new RandomLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}



分区熔断性,就是当集群中的一个服务挂掉后,给他一个默认值,不让他影响整个集群的运行。

io.github.resilience4j
resilience4j-spring-boot2
实现方式一:AOP 式;

public class RecordFailurePredicate implements Predicate{ @Override public boolean test(Throwable throwable) { return true; } } public class IgnoredException extends Exception { }
实现方式二:编程式
无需配置,改造消费者 Service;
@Override
public UserVo getUserVoByUserIDAndCityId(int userId, int cityId) {
UserVo userVo = new UserVo();
User user = userDao.getUserById(userId);
BeanUtils.copyProperties(user,userVo); //copy
// 调用test微服务,获取城市信息,均衡负载方式
// City city = restTemplate.getForObject(
// "http://client-test/api/city/{cityId}", City.class, cityId);
// userVo.setCity(city);
// return userVo;
// 熔断器:就是一个服务挂掉后,给一个默认的值
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
Try circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
circuitBreaker,
() -> restTemplate.getForObject("http://client-test/api/city/{cityId}", City.class, cityId)
)).recover(Exception.class, new City());
userVo.setCity(circuitBreakerSupplier.get());
return userVo;
}

org.springframework.cloud
spring-cloud-starter-openfeign

@Component
@FeignClient(name = "client-test")
public interface TestFeignClient {
/**
*
* /api/city/2259 ------put
*/
@GetMapping(value = "/city/{cityId}")
City selectCityById(@PathVariable int cityId);
}
改造消费者 Service,注入 TestFeignClient,替换掉 RestTemplate;

@Override
public UserVo getUserVoByUserIDAndCityId(int userId, int cityId) {
UserVo userVo = new UserVo();
User user = userDao.getUserById(userId);
BeanUtils.copyProperties(user,userVo); //copy
// 调用test微服务,获取城市信息,均衡负载方式
// City city = restTemplate.getForObject(
// "http://client-test/api/city/{cityId}", City.class, cityId);
// userVo.setCity(city);
// return userVo;
// 熔断器:就是一个服务挂掉后,给一个默认的值
// CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
// .failureRateThreshold(50)
// .waitDurationInOpenState(Duration.ofMillis(1000))
// .build();
// CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
Try circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
// circuitBreaker,
// () -> restTemplate.getForObject("http://client-test/api/city/{cityId}", City.class, cityId)
// )).recover(Exception.class, new City());
// userVo.setCity(circuitBreakerSupplier.get());
// return userVo;
//远程调用
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
Try circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
circuitBreaker,
() -> testFeignClient.selectCityById(cityId)
)).recover(Exception.class, new City());
userVo.setCity(circuitBreakerSupplier.get());
return userVo;
}
}







1.重构 client-test、client-account 接口;







2.创建 Spring Boot 工程 java_spring_cloud_gateway,选择 Eureka Discovery Client、Gateway 组件;




2.配置application.properties,配置account,test的路由和端口
#for server
server.port=8888
# for eureka client
spring.application.name=client-gateway
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8760/eureka
# for gateway route
spring.cloud.gateway.routes[0].id=testServer
# lb load balance 缩写
spring.cloud.gateway.routes[0].uri=lb://client-test
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/test/**
# for gateway route
spring.cloud.gateway.routes[1].id=accountServer
# lb load balance 缩写
spring.cloud.gateway.routes[1].uri=lb://client-account
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/account/**
注册中心: 8760
test微服务: 8761 8762
account微服务:8763 8764
gateway网关:8888

4.启动服务测试




# for Gateway Cros spring.cloud.gateway.globalcors.cors-configurations.[/**].allowCredentials=true spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedOriginPatterns=* spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedMethods=* spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedHeaders=* spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping=true
方式二:配置类
package com.sfac.springCloudGateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Configuration
public class CorsAutoConfiguration {
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeaders().getOrigin());
// 允许的 header
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
"X-Token,Token,Authorization,x-requested-with,Content-Type");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "PUT,POST, GET, OPTIONS, DELETE");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
将微服务的配置文件全部整合一起,然后通过注册中心接口调用然后配置文件。
简介
架构图








org.springframework.cloud
spring-cloud-config-server
注册中心: 8760 test微服务: 8761 8762 account微服务:8763 8764 gateway网关:8888 配置中心:8766
#for server
server.port=
# for eureka client
spring.application.name=client-config
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8760/eureka
# for config server
# 使用本地配置文件,并在工程 resources 下添加相应的文件即可
# spring.profiles.active=native
# 配置文件 Git 仓库地址
spring.cloud.config.server.git.uri=https://gitee.com/ljr666666/config.git
# 配置文件在仓库中文件夹路径
spring.cloud.config.server.git.search-paths[0]=clazz
# 仓库用户名和密码,公有仓库无需设置
#spring.cloud.config.server.git.username=***
#spring.cloud.config.server.git.password=***
# 仓库分支
spring.cloud.config.label=master


1.简介
2.流程
■ 加入bootstrap支持,手动添加,pom
■ 创建bootstrap.properties
■ 拆分application.properties
■ 注册部分,拆解到bootstrap.properties,其余拆解到git仓库对应的配置文件上。
3.实现(改造微服务 Client-Test/Account,其余微服务类似)
-
org.springframework.cloud -
spring-cloud-config-client -
org.springframework.cloud -
spring-cloud-starter-bootstrap
4.重构配置
- Test:bootstrap.properties
-
- #for server
- server.port=8762
-
- # for eureka client
- spring.application.name=client-test
- eureka.instance.hostname=localhost
- eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8760/eureka
-
- #start bootstrap
- spring.cloud.bootstrap.enabled=true;
-
- # for config discovery 开启注册发现
- spring.cloud.config.discovery.enabled=true
- # 指定配置中心 id
- spring.cloud.config.discovery.serviceId=client-config
- # 配置中心中配置文件的名字:{application}-{profile}.properties 中 {application}
- spring.cloud.config.name=applicationTest
-
- # 配置文件“外观”,可以理解为“配置环境占位符”
- spring.cloud.config.profile=dev
- # 配置文件在 git 远程仓库的分支
- spring.cloud.config.label=master
- Account:bootstrap.properties
-
- #for server
- server.port=8763
-
- # for eureka client
- spring.application.name=client-Account
- eureka.instance.hostname=localhost
- eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8760/eureka
-
- #start bootstrap
- spring.cloud.bootstrap.enabled=true
-
- # for config discovery 开启注册发现
- spring.cloud.config.discovery.enabled=true
- # 指定配置中心 id
- spring.cloud.config.discovery.serviceId=client-config
- # 配置中心中配置文件的名字:{application}-{profile}.properties 中 {application}
- spring.cloud.config.name=applicationAccount
- # 配置文件“外观”,可以理解为“配置环境占位符”
- spring.cloud.config.profile=dev
- # 配置文件在 git 远程仓库的分支
- spring.cloud.config.label=master
- # for data source
- # mysql 5
- #spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test_city?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.username=root
- spring.datasource.password=123456
-
- # hikari pool
- spring.datasource.hikari.maximum-pool-size=20
- spring.datasource.hikari.minimum-idle=5
- spring.datasource.hikari.idle-timeout=180000
- spring.datasource.hikari.auto-commit=true
-
- # for mybatis
- mybatis.configuration.map-underscore-to-camel-case=true
- # for data source
- # mysql 5
- #spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- spring.datasource.driver-class-name=com.mysql.jdbc.Driver
- spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test_city?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.username=root
- spring.datasource.password=123456
-
- # hikari pool
- spring.datasource.hikari.maximum-pool-size=20
- spring.datasource.hikari.minimum-idle=5
- spring.datasource.hikari.idle-timeout=180000
- spring.datasource.hikari.auto-commit=true
-
- # for mybatis
- mybatis.configuration.map-underscore-to-camel-case=true
删除 application.properties 或重命名备份;

5. 测试







注册中心:8760
配置中心:8766
test.微服务:8761、8762.
accounL 微服务:8763、8764
前端wcb项目:8765
网关:8888
启动注册中心,访问注册中心页面
启动配置中心,访问注册中心页面,查看注册是否成功,调用配置中心接口,读取配置文件是否成功
启动test微服务,访问注册中心页面,查看注册是否成功
--------
启动网关微服务,访问注册中心页面,查看是否注册成功
对各个微服务接口进行测试
前端文本web项目:
spring mvc




将thmeleaf引进了:
pom,配置
静态资源、页面、页面控制器一直到web微服务,移植拦截器、webMVC配置类(只留下拦截器)
启动项目,检查是否报错,页面能否访问。
修改Ajax请求
页面测试,检查并修复。
spring cloud阶段就打上了句号!继续加油哟!