SpringCloud核心组件实战笔记
课程地址:https://coding.imooc.com/class/187.html
聚合:对多个api调用逻辑进行聚合来减少客户端请求数
裁剪:根据不同的需求返回不同的数据,例:pc端返回html,app端返回json,显然pc端更详细
spring cloud eureka是基于netflix eureka做了二次封装
eureka:
client:
service-url:
defaultZone: http://localhost:8080/eureka/
register-with-eureka: false
server:
enable-self-preservation: false//关闭上线率检测
多台机器的eureka需要两两注册,两台交叉注册
client注册到所有的eureka上面
康威定律
通信方式
restTemplate
//第一种方式(直接使用restTemplate,url写死)
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject("http://localhost:8080/msg",String.class);//url,返回类型
//第二种方式(利用loadBalancerClient通过应用名称获取url,让后使用restTemplate)
@Autowired
private LoadBalancerClient loadBalancerClient;
RestTemplate restTemplate = new RestTemplate();
ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");
String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort())+"/msg";
String response = restTemplate.getForObject(url,String.class);
//第三种方式(@LoadBalanced,可在restTemplate里面使用应用名字)
@Component
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Autowired
private RestTemplate restTemplate;
String reponse = restTemplate.getForObject("http://Product/msg",String.class);
ribbon
自定义负载均衡策略
PRODUCT:
ribbon:
NFLoadBalancerRuleClassName: com.netfix.loadbalancer.RandomRule//默认轮询,这里改成随机策略
feign(采用了基于接口的注解)
@FeignClient(name = "product")
public interface ProductClient {
@GetMapping("/msg")
String productMsg();
}
反序列化失败,可能是缺少无参构造方法
统一配置中心
需要配置远程git
关系远端git-----config server -----本地git
cloud:
config:
server:
git:
uri:
username:
password:
basedir://本地配置文件存放位置
/{name}-{profiles}.yml
/{label}/{name}-{profiles}.yml
name 服务名
profiles环境
label分支
先启动再去拉取配置需要改成bootstrap.yml
找不到id
客户端先去注册中心找config server ,没有发现远端git将注册中心改成8762,默认会使用8761的地址,这个时候就要拿出来配置
eureka:
client:
service-url:
defaultZone: http://localhost:8762/eureka/
远端git有多个配置文件注册到config server他会根据文件名类型将多个文件整合
springCloud Bus自动刷新配置,rabbitmq通知配置变更
使用Finchley.BUILD-SNAPSHOT这个版本和spring-cloud-starter-bus-amqp组件
注意升级版本后,spring-cloud-starter-feign改名成spring-cloud-starter-openfeign了
要对属性哪些配置做刷新记得在类上加@RefreshScope
记得暴露刷新api接口
management:
endpoints:
web:
expose: "*"
配置自动访问/bus-refresh 接口
在远程仓库配置自动刷新
选择webhooks
点击add webhook
填写payloadURL地址http:ip/monitor
填写Content type 选applicationn/json
然后更改远程git配置文件就能实现动态刷新
rabbitmq
1、@RabbitListener(queues = "myQueue")
2、自动创建队列@RabbitListener(queuesToDeclare = @Queue("myQueue"))
3、自动创建,Exchange和Queue绑定
@RabbitListener(bindings = @QueueBinding(
value = @Queue("myQueue"),
exchange = @Exchange("myExchange")
))
public void process(String message) {
log.info("MqReceiver:{}",message);
}
只接受带key的消息
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange("myOrder"),
key = "fruit",
value = @Queue("fruitQueue"),
))
public void process(String message) {
log.info("MqReceiver:{}",message);
}
spring cloud stream对中间件封装
定义
public interface StreamClient {
String INPUT = "myMessage";
@Input(StreamClient.INPUT)
SubscribableChannel input();
@Output(StreamClient.INPUT)
MessageChannel output();
}
接收端
@Component
@EnableBinding(StreamClient.class)
@Slf4j
public class StreamReceiver {
@StreamListener(StreamClient.INPUT)
public void process(Object message){
log.info("StreamReceiver:{}",message);
}
}
发送端
@RestController
public class StreamSend {
@Autowired
private StreamClient streamClient;
@GetMapping("/sendMessage")
public void process(){
String message = "now" + new Date();
streamClient.output().send(MessageBuilder.withPayload(message).build());
}
}
配置分组
spring:
application:
stream:
bindings:
myMessage:
group: order
content-type: application/json //不用在编码里面序列化和反序列化就可查看堆积消息内容
实现接收消息的回应,添加@SendTo()
@StreamListener(value = StreamClient.INPUT)
@SendTo(StreamClient.INPUT2)
public String process(OrderDTO message) {
log.info("StreamReceiver:{}",message);
return "received";
}
@StreamListener(value = StreamClient.INPUT2)
public void process(String message) {
log.info("StreamReceiver:{}",message);
}
订单失败回滚时,消息已经发送,那么就需要将事务单独提取出一个方法
zuul
zuul:
sensitive-headers:#全局可传递cookie
routes:
myProduct:
path: /myProduct/**
serviceId: product
sensitiveHeaders: #这里设置为空,方便获取cookie
#简介写法
product: /myProduct/**
#排除某些路由
ignored-patterns:
- /**/product/listForOrder
#查看所有路由配置,要关闭权限校验,访问localhost:端口/application/routes
management:
security:
enabled: false
动态配置路由
可以新建一个类添加@Componet注解
或者加到启动类
@ConfigurationProperties("zuul")
@RefreshScop
public ZuulProperties zuulProperties() {
return new zuulProperties();
}
限流早于鉴权
继承ZuulFilter实现方法
//令牌数量
private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);
//调高优先级
@Override
public int filterOrder()
{
return SERVLET_DETECTION_FILTER-ORDER - 1;
}
//处理令牌
@Override
public Object run() {
if(!RATE_LIMITER.tryAcquire()) {
throw new RateLimitException();
}
return null;
}
设置cookie+redis
public static void set(HttpServletRespose response,
String name,
String value,
int maxAge) {
Cookie cookire = new Cookie(name, value);
cookie.setPath("/");
cookie.setMaxAge(maxAge);
response.addCookie(cookie);
}
//使用
String token = UUID.randomUUID().toString();
Integer expire = CookieConstant.expire;
stringRedisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_TEMPLATE,token),
openid,
expire,
TimeUnit.SECONDS);
CookieUtil.set(response, CookieConstant.OPENID, openid,CookieConstant.expire);
//防止刷新导致redis里面存多个key
public static Cookie get(HttpServletRequest request,
String name) {
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for(Cookie cookie: cookies) {
if(name.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
//使用
Cookie cookie = CookieUtil.get(request,CookieConstant.TOKEN);
if(cookie != null &&
!StringUtils.isEmpty(stringRedisTemplate.opsForValue().get(RedisConstant.TOKEN_TEMPLATE,cookie.getValue()))){
return ResultVOUtil.success();
}
zuul鉴权
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
if("/order/order/create".equals(request.getRequestURI())) {
return true;
}
retrun false;
}
zuul跨域配置
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setMaxAge(300l);
source.registerCorsConfiguration("/**",config);
return new CorsFilter(source);
}
}
spring cloud hystrix
服务降级
优先核心服务,非核心服务不可用或弱可用
通过HystrixCommand注解指定
fallbackMethod(回退函数)中具体实现降级逻辑
@SpringCloudApplication=@SpringBootApplication+@EnableDiscoveryClint+@EnableCircuitBreaker
//当然服务降级不止应用于服务,出现错误可以用降级处理
@RestController
//配置默认降级方法
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})//配置服务超时时间/进入降级时间
//服务熔断
@HystrixCommand(commandProperties = {
@HystrixProperty(name ="circuitBreaker.enabled",value = "true"),//设置熔断
@HystrixProperty(name ="circuitBreaker.requestVolumeThreshold",value = "10"),
@HystrixProperty(name ="circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
@HystrixProperty(name ="circuitBreaker.errorThresholdPercentage",value = "60"),
@HystrixCommand(fallbackMethod = "fallback")
@GetMapping("/getProductInfoList")
public String getPoductInfoList() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForObject("http://127.0.0.1:8005/product/list",
Arrays.asList("1578832904"),
String.class);
}
private String fallback() {
return "太拥挤了,请稍后再试"
}
}
//熔断器有三个状态,打开,关闭,半开状态,出问题会先进入半开状态,失败次数超过窗口设置阈值就会打开
yaml配置,记得在降级方法上面加@HystrixCommand注解,否则不生效
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
getProductInfoList://针对方法降级
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
hystrix-dashboard
导入依赖,加上@EnableHystrixDashboard
management:
context-path: /
访问:ip:port/hystrix.stream
第一次启动项目有时候会超时?因为懒加载,刚开始可以将超时时间设置长一些
链路监控
Spring Cloud Sleuth
通过zipkin外部面板观察链路
zipkin:
base-url: http://localhost:9411/
sleuth:
sampler:
percentage: 1
访问:localhost:9411/zipkin/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
2022-02-05 递归需要遵守的重要规则