转载:https://mp.weixin.qq.com/s?__biz=Mzg3Mjk3OTA4OA==&mid=2247484243&idx=1&sn=7011f471fad70679dfc89505f186d36e&chksm=cee64cacf991c5baf3b32559f86500a7c12aaa25cf7df6e8ed8b575f612650b1218cb686d89a&cur_album_id=2973104649560178694&scene=189#wechat_redirect
java -jar sentinel-dashboard-1.8.1.jar
如果你需要修改默认的配置端口,可以使用以下命令:
java -Dserver.port=8090 -jar sentinel-dashboard-1.8.1.jar
启动成功后访问http://localhost:8080页面,就可以看到sentinel的控制台了,输入默认的用户名和密码 sentinel
一开始进来是空白的,这时候他没有监控到任何的服务,因为这时候我们还没有整合到项目中。
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
server:
port: 8082
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
打开浏览器,访问http://localhost:8088/order/102,这样才能触发sentinel的监控。
然后再访问sentinel的控制台,查看效果:
@GetMapping("/update")
public String update() {
return "更新库存成功";
}
@GetMapping("/select")
public String select() {
return "查询库存成功";
}
public void queryGoods(){
System.out.println("查询商品");
}
@GetMapping("/query")
public String queryOrder() {
// 查询商品
orderService.queryGoods();
// 查询订单
System.out.println("查询订单");
return "查询订单成功";
}
@GetMapping("/save")
public String saveOrder() {
// 查询商品
orderService.queryGoods();
// 查询订单
System.err.println("新增订单");
return "新增订单成功";
}
@SentinelResource("goods")
public void queryGoods(){
System.out.println("查询商品");
}
spring:
cloud:
sentinel:
web-context-unify: false # 关闭context整合
1)标记资源
给order-service中的OrderController中的/order/{orderId}资源添加注解:
@SentinelResource("hot")
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
return orderService.queryOrderById(orderId);
}
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
package cn.itcast.feign.fallback;
import cn.itcast.feign.client.UserFeignClient;
import cn.itcast.feign.pojo.User;
import feign.hystrix.FallbackFactory;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class UserClientFallback implements FallbackFactory<UserFeignClient> {
@Override
public UserFeignClient create(Throwable cause) {
log.error("UserClientFallback create fallback err:{}",cause.getMessage());
/*降级的方法,queryById调用异常后的兜底方案*/
return new UserFeignClient() {
@Override
public User queryById(Long id) {
return new User();
}
};
}
}
package cn.itcast.feign.config;
import cn.itcast.feign.fallback.UserClientFallback;
import feign.Logger;
import org.springframework.context.annotation.Bean;
public class DefaultFeignConfiguration {
@Bean
public UserClientFallback setUserClientFallback(){
return new UserClientFallback();
}
}
package cn.itcast.feign.client;
import cn.itcast.feign.fallback.UserClientFallback;
import cn.itcast.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "user-service", fallbackFactory = UserClientFallback.class)
public interface UserFeignClient {
@GetMapping("/user/{id}")
User queryById(@PathVariable("id") Long id);
}
package cn.itcast.user.service;
import cn.itcast.user.mapper.UserMapper;
import cn.itcast.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryById(Long id) {
//模拟如果id为103的请求为慢查询
if(id == 3){
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return userMapper.findById(id);
}
}
3)测试
在浏览器访问:http://localhost:8082/order/103,快速刷新5次,可以发现:
第一次正常响应
package cn.itcast.user.service;
import cn.itcast.user.mapper.UserMapper;
import cn.itcast.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryById(Long id) {
//模拟代码执行异常
if(id == 3){
throw new RuntimeException("模拟代码执行异常!!!");
}
return userMapper.findById(id);
}
}
public interface RequestOriginParser {
/**
* 从请求request对象中获取origin,获取方式自定义
*/
String parseOrigin(HttpServletRequest request);
}
package cn.itcast.order.sentinel;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
@Component
public class HeaderOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// 1.获取请求头
String origin = request.getHeader("origin");
// 2.非空判断
if (StringUtils.isEmpty(origin)) {
origin = "blank";
}
return origin;
}
}
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=origin,gateway
public interface BlockExceptionHandler {
/**
* 处理请求被限流、降级、授权拦截时抛出的异常:BlockException
*/
void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
}
package cn.itcast.order.sentinel;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
String msg = "未知异常";
int status = 429;
if (e instanceof FlowException) {
msg = "请求被限流了";
} else if (e instanceof ParamFlowException) {
msg = "请求被热点参数限流";
} else if (e instanceof DegradeException) {
msg = "请求被降级了";
} else if (e instanceof AuthorityException) {
msg = "没有权限访问";
status = 401;
}
response.setContentType("application/json;charset=utf-8");
response.setStatus(status);
response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");
}
}