分布式 > 微服务 > SpringCloud
客户端处理: 负载均衡{Ribbon Feign),断路器中的服务降级 都是是客户端处理
服务端处理:断路器中的服务熔断
一。父工程构建
新建父工程microservicecloud,主要是定义POM文件,将后续子模块公用的jar包统一提出来,类似一个抽象父类
***注意packaging是POM模式***
二。公共子模块API构建(定义一个实体类供各个模块引用)
1.新建模块 cloud-zero-api
2.pom
<parent>自动生成
<artifactId>当前Module名称
3.实体类创建
4.其他模块引用
<dependency>
<groupId>com.wind</groupId>
<artifactId>cloud-zero-api</artifactId>
<version>${project.version}</version>
</dependency>
三。服务提供者构建
1.新建模块 provider
2.pom
<parent> 自动生成
<artifactId> 当前module名称
<depency>公用API模块
3.application.yml
a.端口 :8001
b.Spring 本微服务名称 和数据库连接信息
c.mybatis 映射文件和实体类所在包
server:
port: 8001
spring:
application:
name: cloud-zero-user-8001服务提供者
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud-zero?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: root
mybatis:
type-aliases-package: com.wind.cloud.demo.user.domain # 所有Entity别名类所在包
mapper-locations:
- classpath:mapper/*.xml # mapper映射文件
4. dao service control增删改查
5. 启动类
测试 localhost:8001/user/list 显示数据
四。将服务注册
a.服务注册中心(7001)建立
Netflix在设计eureka遵循AP原则
自我保护机制:好死不如赖活着(保留错误信息也不删除)
//1.新建模块
//2.pom 添加相关技术依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
//3.yml 端口与配置
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #其他微服务注册进来的地址
#defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
//4.启动类
@SpringBootApplication
@EnableEurekaServer 表示7001是服务端启动类 ,接收其他微服务注册进来
测试是否成功:localhost:7001有出现eureka界面就是表示Ok
b。将已有的服务(8001)注册进Eureka(7001)
//1.pom 引入eureka-client 8001的pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
//2.yml 8001的yml
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
defaultZone: http://eureka7001.com:7001/eureka, 星云:defaultZone: http://192.168.1.15:8572/eureka/
http://eureka7002.com:7002/eureka,
http://eureka7003.com:7003/eureka #//是7001里面的defaultZone的地址
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
prefer-ip-address: true
info:
app.name: cloud-zero
company.name: www.zmrit.com
build.artifactId: hahaha
build.version: 2020032001
/3.主启动类 添加注解
@EnableEurekaClient 表示8001服务启动后会自动注册进eureka服务中
测试是否成功:先启动7001再启动8001,输入 localhost:7001 出现的界面中Application有内容就表示注册成功
c.Eureka界面信息修改 完善
在服务提供者模块
1.修改显示的微服务名称Application
8001.yml
spring:
application:
name: cloud-zero-user
2.修改超链接显示的内容,和左下角显示的Ip
8001.yml
eureka下添加 instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} //超链接显示的内容
prefer-ip-address: true # 访问路径可以显示IP地址 //左下角显示的内容
3.修改点击超链接跳出来显示的内容
a. 8001.pom添加监控依赖信息
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
b. 父工程 pom文件添加构建信息build 可以为空标签
c. 8001.yml添加 info,与server spring mybatis同等级
info:
app.name: cloud-zero
company.name: www.zmrit.com
build.artifactId: aaa
build1.version: bbb
build12.version2: ccc
test.test: aaa
4.修改服务注册地址
7001 yml的 DefaultZone 和 8001yml的defaultZone
d.Eureka集群配置
1.新建molule,复制7001模块
2.修改host映射配置 作用:使用别名区分不同服务中心
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
3.修改yml a.端口/b.hostname/c.defaultZone
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 单机写7001
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ 集群的话写7002和7003
4.修改8001的yml defaultZone:注册地址由单机改完集群
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
f.Eureka服务发现
什么是服务发现:对于注册进eureka里面的微服务,我们可以通过服务发现来获取该服务的发现
1.服务提供者的控制器加上如下内容 8001
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "discovery", method = RequestMethod.GET)
@ResponseBody
public Object discovery()
{
List<String> list = client.getServices();
System.out.println("**********" + list);
List<ServiceInstance> srvList = client.getInstances("cloud-zero-USER");
for (ServiceInstance element : srvList)
{
System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
+ element.getUri());
}
return this.client;
}
2.还是这个控制器加上 @EnableDiscoveryClient //服务发现
注册到Nacos
1.启动nacos服务,测试访问:http://localhost:8848/nacos 账号:nacos 密码:nacos
2.微服务注册到nacos
1.pom引入依赖,版本要和项目的springboot一致
<!--服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
2.yml文件指定注册中心(要给这个服务起名字spring.application.name)
spring:
application:
name: mock
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: 环境隔离dev uuid
3.主启动类加注解@EnableDiscoveryClient, 也可不用加
4.测试访问nocos服务列表看是否有这个服务
五。消费者 restTemplate
消费者理解为:新加另一种访问路径来访问provider,
端口一般设为80就可以省略端口
1.新建模块 cloud-zero-consumer-user
2.pom 见最底下5.2
<dependencies>
3.yml
端口 将服务注册进eureka 见最底下5.3
4.新建 ConfigBean 获取restTemplate 见最底下5.4
5,新建控制器 ConsumerUserController 根据Http工具restTempate发送请求 见最底下5.5
restTepmplate(url,参数,返回类型) url为服务提供者的url
6.启动类 @EnableEurekaClient
测试:启动提供者8001 再启动消费者80,通过80的网址也能查到数据表示Ok
六。Ribon 负载均衡
1.初步配置 (prefix由微服务名称代替ip+端口)
Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号
根据服务名称查询Eureka注册中心的可用列表并轮询
//在80模块 消费者
1.pom添加 ribbon依赖
<!-- Ribbon相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2.configBean的方法添加注解lb @LoadBalanced
3.consumer访问控制器
private static final String REST_URL_PREFIX = "http://localhost:8001"; 改为
private static final String REST_URL_PREFIX = "http://CLOUD-ZERO-USER";
测试:启动三个注册中心 服务提供者 消费者,看80是否还能正常访问
2.多个微服务提供者负载均衡测试 (多个服务提供者,连接多个库)
1.新建模块provider-user-8002 和provider-user-8003
pom拷贝8001
yml 改端口和数据库地址 (注意:服务名称不能改 spring.application.name)
2.测试
a.启动三个注册中心 启动三个微服务提供者(并自测通过) 启动消费者
访问消费者 http://localhost/consumer/user/list 每次去查的库不一样
3.指定Ribbon提供的算法
在configBean添加如下代码 (如果不加默认采用RoundRobinRule轮询)
//在configBean添加
@Bean
public IRule myRule(){
return new RandomRule(); //指定算法代替默认的轮询算法
}
4…自定义算法
//在80模块
1.添加文件 MySelfRule.class 文件见最底下 6.4的第二种的第一个类
注意:a.该文件不能在80主启动类的包以子包下(该类所在的包 和启动类所在的包同等级)
b.该文件类名加@Configuration 方法加@bean
2. 自定义算法MyRandomRule.class(参考源码地址) 文件见最底下 6.4的第二种的第二个类
3.80的主启动类添加注解
@RibbonClient(name = "USER-PROVIDER", configuration = MySelfRule.class) //name服务提供者名称 configuration:自定义算法文件
1.添加文件 public class MyRandomRule extends AbstractLoadBalancerRule
2.mySelf文件 改为 return new MyRandomRule();//我自定义为每个机器被访问5次
七 Feign 负载均衡
小程序调用运营平台的功能 ,
如下写在调用方小程序(接口加注解的方式)
1.调用方声明提供方的微服务名称和接口路径
@FeignClient(name = "newenergy-operation-manage-0-0-1",configuration = FeignClientConfiguration.class)
public interface HomePageFeignClient {
@PostMapping("/api/basic/search/byPricePlanId")
PricePlanAndDetailsDto getPricePlan(@RequestBody PricePlanDto planId);
@PostMapping("/api/basic/search/priceRule")
List<PriceRuleAndDetailsDto> searchPriceRule(@RequestBody List<String> ids);
@PostMapping("/api/park/manage/add/reduction/recordByParkAPI")
Integer addParkReductionRecordByParkAPI(@RequestBody ParkReduceAPIRequestDto requestDto);
}
2.调用方调用使用
homePageFeignClient.addParkReductionRecordByParkAPI(requestDto);
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
Feign可以与Eureka和Ribbon组合使用支出负载均衡
Feign通过接口的方法调用服务,之前是Ribbon + restTemplate
Feign集成了Ribbon,并且通过轮询实现了负载均衡功能,而与Ribbon不同的是,Feigh只需要定义接口和添加注解,就可以实现服务的调用
简写:Feign是一个声明式的服务客户端,使得编写Web服务客户端变得非常容易(用接口代替微服务调用rest)
1.API.pom添加Feign依赖
<!-- Fegin相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.API新建接口文件 RemoteUserService(注意有注解 @FeignClient(value = "CLOUD-ZERO-USER"))
3.消费者修改Controller的调用方式 (从微服务名称改为接口)
4.消费者启动器去掉@RibbonClient注解,去掉ribbon的作用,注解新增@EnableFeignClients
OpenFeign
只要在调用方处理就好,dubbo服务提供方还要做接口暴露处理(@service)
比如用户服务调用订单服务,如下操作都在用户服务调用方
1.pom引入依赖spring-Cloud-start-openfeign
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
2.主启动类添加@EnableFeignClients注解
3.添加OrderFeignService接口,接口上加@FeignClient注解(value为订单微服务名称在nacos看,path为订单服务的总路径),接口下加方法(可直接复制订单的控制层)
@FeignClient(value = "substationserver", path = "/api/core")
public interface AzxtFeignService {
@GetMapping("/getRouteByCubicle") //服务提供方的接口路径为 /api/core/getRouteByCubicle
List<Object> getRouteByCubicle(@RequestParam String cubicleId);
}
4.在用户模块的控制层,依赖注入@Aotuwired OrderFeignService orderFeignService,然后orderFeignService.methodName()
老林
星云调用微信接口
String userInfo = wxFeignClient.getUserInfo(accessTokenDTO.getAccess_token(), accessTokenDTO.getOpenid());
package com.nebula.microservice.authorization.user.feign;
import com.nebula.microservice.authorization.user.constant.UserConstants;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "wx", url = UserConstants.WX_AUTH_URL)
public interface WXFeignClient {
/**
* 微信小程序授权
*
* @param appId 小程序 appId
* @param secret 小程序 appSecret
* @param jsCode 登录时获取的 code
* @param grantType 授权类型,此处只需填写 authorization_code
* @return 响应消息json
*/
@GetMapping("/sns/jscode2session")
String jsCode2Session(@RequestParam(name = "appid") String appId,
@RequestParam(name = "secret") String secret,
@RequestParam(name = "js_code") String jsCode,
@RequestParam(name = "grant_type") String grantType);
/**
* 根据前端传来的code获取access_token
*
* @param appId 应用唯一标识,在微信开放平台提交应用审核通过后获得
* @param secret 应用密钥 ,在微信开放平台提交应用审核通过后获得
* @param code 填写第一步获取的 code 参数
* @param grantType 授权类型,此处只需填写 authorization_code
* @return
*/
@GetMapping("/sns/oauth2/access_token")
String getAccessToken(
@RequestParam(name = "appid") String appId,
@RequestParam(name = "secret") String secret,
@RequestParam(name = "code") String code,
@RequestParam(name = "grant_type") String grantType
);
/**
* 根据access_token和openid获取微信用户个人信息
*
* @param access_token 调用凭证
* @param openid 普通用户的标识,对当前开发者帐号唯一
* @return
*/
@GetMapping("/sns/userinfo")
String getUserInfo(
@RequestParam(name = "access_token") String access_token,
@RequestParam(name = "openid") String openid
);
/**
* 刷新access_token
*
* @param appid
* @param grant_type
* @param refresh_token
* @return
*/
@GetMapping("/sns/oauth2/refresh_token")
String refreshToken(
@RequestParam(name = "appid") String appid,
@RequestParam(name = "grant_type") String grant_type,
@RequestParam(name = "refresh_token") String refresh_token
);
/**
* 验证access_token是否有效
*
* @param access_token
* @param openid
* @return
*/
@GetMapping("/sns/auth")
String tokenIsValid(
@RequestParam(name = "access_token") String access_token,
@RequestParam(name = "openid") String openid
);
}
八 Hystrix 断路器
Hystrix是一个处理分布式系统延迟和容错的开源库
作用:保证在某个依赖挂断的情况下,不会导致整个服务系统也跟着挂掉,避免级联故障
服务熔断 服务降级 服务限流 接近实时的监控
源码地址
1.服务熔断
异常调用额外的方法
如下都在provider模块修改
1. pom(provider)添加Hystrix依赖
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2. 修改Eureka界面超链接显示的内容 (见上方) 这部分主要是为了突出显示它是Hystrix 不操作也行
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
3. UserController 查询方法添加注解 @HystrixCommand(fallbackMethod = "processHystrix_Get") 并添加方法 processHystrix_Get
@GetMapping("/{id}")
@ResponseBody
@HystrixCommand(fallbackMethod = "processHystrix_Get")
public User selectUserByGuid(@PathVariable Integer id){
User user = userMapper.selectUserById(id);
if (null == user){
throw new RuntimeException("异常信息啊啊啊");
}
return user;
}
//如果查询不到user,会调用这个方法
public User processHystrix_Get(@PathVariable Integer id){
return new User().setId(id).setName("该ID:" + id + " 没有对应的信息,null").setAge(0);
}
4. 主启动类添加新注解 @EnableCircuitBreaker
测试: 启动三个Eureka 启动服务提供者 启动带熔断服务的Consumer getById查一个不存在的id
2.服务降级
概念: 整体资源快不够了,忍痛将某些服务关掉,待度过难关再开启回来
/**上面服务熔断有两个缺点:
1.每个方法都要加一个注解和一个回调方法,方法膨胀(即太多方法)
2.业务主逻辑和异常逻辑混合在一起,耦合性太高()*/
在API模块
1.新建一个类 该类实现FallbackFactory<RemoteUserService> //RemoteUserServices是在Feign时就建立的,当时是为了利用接口调用服务代替Ribbon + restTemplate
注意:记得在该新建的类上面添加注解:@Component
2.修改RemoteUserService注解 @FeignClient(value = "CLOUD-ZERO-USER", fallbackFactory = RemoteUserFacllbackFactory.class)
3.Cunsumer模块的yml文件添加
feign:
hystrix:
enabled: true
测试: 启动三个Eureka 启动Provider
3.监控台 HystrixDashboard 豪猪
//1.新建模块HystrixDashboard
//2.pom 见最底下8.3
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--hystrix-dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
3.启动器
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApp{
public static void main(String[] args){
SpringApplication.run(HystrixDashboardApp.class);
}
}
4.yml
spring:
application:
name: cloud-zero-hystrix-dashboard
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
#defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
prefer-ip-address: true # 访问路径可以显示IP地址
management:
endpoints:
web:
exposure:
include: '*'
info:
app.name: cloud-zero
company.name: www.zmrit.com
build.artifactId: @project.artifactId@
build.version: @project.version@
server:
port: 9050
5.服务提供者的yml添加如下,否则报404
management:
endpoints:
web:
exposure:
include: '*'
6.服务提供者8001 8002等的pom都要有监控依赖
<!--监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
测试一: 单独启动hystrixdashboard模块,http://localhost:9001/hystrix ,出现哥豪猪,ok
测试二:启动三个eureka注册中心,启动带hystrix(服务熔断)的服务提供者8004,启动hystrixDashboard 用dashboard来监控微服务8004
访问 http://localhost:8004/user/list 8004正常启动
访问 http://localhost:8004/hystrix.stream 出现ping
豪猪哥页面 输入http://localhost:8004/hystrix.stream,dela栏位输入2000ms,title栏位输入demo001,点击monitor stream ,出现图像化界面
九 Zuul服务网关
网关作用:
服务路由
超时处理
熔断处理
限流控制
日志记录
灰度发布
负载均衡
认证授权
1.新建模块cloud-zero-gateway 9527
2.pom
<dependencies>
<!--gateway 网关依赖,内置webflux 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
3.主启动类 @EnableDiscoveryClient
4.yml 见最底下9.4
启动eureka 启动服务提供者 启动gateway
http://localhost:8001/user/selectUserById 能访问
http://gateway.com:9527/USER-PROVIDER/user/selectUserById 通过路由也能方法 (网关 + 微服务名称 + 微服务里面的访问路径)
把访问路径中的 USER-PROVIDER(微服务名称) 自定义
9527模块的yml文件spring添加如下
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
#system 模块
- id: cloud-zero-user
uri: lb://USER-PROVIDER
predicates:
- Path=/test/**
filters:
- StripPrefix=1
十 Config 配置中心
github上传配置文件步骤
1.在github新建仓库cloud-zero-config并clone到本地
2.在文件夹cloud-zero-config新建application.yml并提交到gitHub,注意文件另存为utf-8
1.新建模块 cloud-zero-config2
2.pom
3.yml
4.主启动类加注解 @EnableConfigServer
测试:http://127.0.0.1:3344/application-dev.yml
http://127.0.0.1:3344/application-test.yml (最后面的application-test.yml有五种写法)
十一 SpringCloud GateWay 网关
1.pom引入依赖
//和springboot项目大致相同, 只是不需要spring-boot-starter-web并且网关的版本为2.2.1
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
<dependencies>
<!-- nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<!--Nacos配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<!--gateway网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
</dependencies>
2.配置路由 spring.cloud.gateway
2.1 yml方式配置路由
server:
port: 8089
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true #1.默认为false,设为true开启通过微服务创建路由的功能,既可以通过微服务名访问服务
enabled: true # 是否开启网关
routes:
- id: mock #id自定义
uri: lb://mock #本来是localhost:8001,换成被调用方微服务名称
//uri: http://energy-cloud-pay-gateway-enetest.local.evota.com 或者直接域名
predicates:
- Path=/mock/**
nacos:
discovery:
server-addr: localhost:8848
2.2 硬编码方式配置路由
配置路由里面的predicete详解
匹配访问请求
1.after: //yml配置:- After=2020-02-21
2.before
3.between
4.cookies // yml配置:-cookie=userName,zzyy 测试路径:localhost:9527/user/get --cookie="userName=zzyy"
5.headers
6.host // yml配置:- host=**.atguigu.com 测试路径:localhost:9527/user/get --H "Host:news.atguigu.com"
7.method //- method=get
8.path //- Path=/api/**
9.query //- Query=userName,\d+ 要有参数名userName并且值要为整数
10.remoteAddr
11.weight route
网关过滤器,
拦截请求做额外处理
1.Spring Cloud GateWay的生命周期
pre和Post:业务逻辑之前和业务逻辑之后,类似与SpringAop的前置通知和后置通知
2.种类
Gateway Filter和 Global Filter (单一和全局)
3.自定义过滤器
a.实现方式:implements Global Fileter,Orderes
b.能干嘛:全局日志配置,统一网关鉴权
概览
5.2 消费者pom
<dependencies>
<!--eureka 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--api模块-->
<dependency>
<groupId>com.wind</groupId>
<artifactId>cloud-zero-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>@</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
5.3 消费者的yml
server:
port: 80
spring:
application:
name: user-consumer
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
defaultZone: http://eureka7001.com:7001/eureka,
http://eureka7002.com:7002/eureka,
http://eureka7003.com:7003/eureka #//是7001里面的defaultZone的地址
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
prefer-ip-address: true
info:
app.name: consumer
version: 20200317
5.4 ConfigBean
@Configuration
public class ConfigBean{
@Bean
//@LoadBalanced 需要负载均衡加此注解
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
5.5 consumerController
@RestController
@RequestMapping("user")
public class ConsumerUserController{
private static final String REST_URL_PREFIX = "http://localhost:8001";
/**
* 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
* ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
*/
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "add")
public boolean add(User user){
return restTemplate.postForObject(REST_URL_PREFIX + "/user/add", user, Boolean.class);
}
@RequestMapping(value = "get/{id}")
public User get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX + "/user/get/" + id, User.class);
}
@SuppressWarnings("unchecked")
@RequestMapping(value = "list")
public List<User> list(){
return restTemplate.getForObject(REST_URL_PREFIX + "/user/list", List.class);
}
// 测试@EnableDiscoveryClient,消费端可以调用服务发现
@RequestMapping(value = "discovery")
public Object discovery(){
return restTemplate.getForObject(REST_URL_PREFIX + "/user/discovery", Object.class);
}
}
6.2 多个服务提供者的pom
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.wind</groupId>
<artifactId>cloud-zero-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
6.4 MySelfRule 负载均衡自定义算法
类加@Configuration 方法加@Bean
//第一种 Ribbon提供的
@Configuration
public class MySelfRule {
@Bean
public IRule diy(){
return new RoundRobinRule();
}
}
//第二种 自定义 比第一种多一个文件
@Configuration
public class MySelfRule{
@Bean
public IRule myRule(){
return new MyRandomRule();
}
}
public class MyRandomRule extends AbstractLoadBalancerRule{
// total = 0 // 当total==5以后,我们指针才能往下走,
// index = 0 // 当前对外提供服务的服务器地址,
// total需要重新置为零,但是已经达到过一个5次,我们的index = 1
// 分析:我们5次,但是微服务只有8001 8002 两台,OK?
//
private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
private int currentIndex = 0; // 当前提供服务的机器号
public Server choose(ILoadBalancer lb, Object key){
if (lb == null){
return null;
}
Server server = null;
while (server == null){
if (Thread.interrupted()){
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0){
return null;
}
if (total < 5){
server = upList.get(currentIndex);
total++;
}else{
total = 0;
currentIndex++;
if (currentIndex >= upList.size()){
currentIndex = 0;
}
}
if (server == null){
Thread.yield();
continue;
}
if (server.isAlive()){
return (server);
}
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key){
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig){
}
}
8.3 hystirxdashboard的pom
<dependencies>
<!--api-->
<dependency>
<groupId>com.wind</groupId>
<artifactId>cloud-zero-api</artifactId>
<version>${project.version}</version>
</dependency>
<!--springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
测试一: 单独启动hystrixdashboard模块,http://localhost:9001/hystrix ,出现哥豪猪 ,ok
测试二
9.4 yml
server:
port: 9527
spring:
application:
name: cloud-zero-gateway
devtools:
restart:
enabled: true
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
#system 模块
- id: cloud-zero-user
uri: lb://cloud-zero-user
predicates:
- Path=/serve-user/**
filters:
- StripPrefix=1
eureka:
client: # 客户端注册进eureka服务列表内
service-url:
defaultZone: http://eureka7001.com:7001/eureka,
http://eureka7002.com:7002/eureka,
http://eureka7003.com:7003/eureka #//是7001里面的defaultZone的地址
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
prefer-ip-address: true
info:
app.name: cloud-zero-gateway
company.name: www.zmrit.com
build.artifactId: aaa
build1.version: bbb
build12.version2: ccc
test.test: aaa
10.2.POM
<dependencies>
<!--配置中心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--web 模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除tomcat依赖 -->
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--undertow容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
10.3 yml
//配置中心3344的yml文件
server:
port: 3344
spring:
application:
name: cloud-zero-config
# 配置中心
cloud:
config:
server:
git:
# 修改成你自己的git仓库
uri: https://github.com/piaoransheng/cloud-zero-config.git
//上传到gitHub上的文件
spring:
profiles:
active: dev
---
spring:
profiles: dev #开发环境
application:
name: cloud-zero-config-dev
---
spring:
profiles: test #测试环境
application:
name: cloud-zero-config-test
# 请保存为UTF-8格式