spring拦截器 实现应用之性能监控
2023-09-11 14:19:52 时间
package cn.ximi.erp.web.common.interceptors; import cn.ximi.core.common.utils.string.StringUtil; import cn.ximi.erp.web.constant.Constants; import cn.ximi.erp.web.base.UserContext; import cn.ximi.manage.entity.SysResource; import cn.ximi.manage.entity.SysUser; import cn.ximi.manage.service.ResourceService; import cn.ximi.manage.service.SysUserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.NamedThreadLocal; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.Set; /** * 登录拦截器 * ( * 实现应用之性能监控 * 拦截器是实现成单例的,因此不管用户请求多少次都只访问同一个拦截器实现,即线程不安全。 * 解决方案是:使用ThreadLocal,它是线程绑定的变量,提供线程局部变量(一个线程一个ThreadLocal, * A线程的ThreadLocal只能看到A线程的ThreadLocal,不能看到B线程的ThreadLocal)。 * ) * Created by gmq on 2016/4/28. */ public class LoginInterceptor implements HandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class); // 统计应用性能 private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("StopWatch-StartTime"); @javax.annotation.Resource private SysUserService sysUserService; @Autowired private ResourceService resourceService; private Set<String> excludeURIs; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 设置起始时间 // 1、开始时间 long startTime = System.currentTimeMillis(); // 线程绑定变量(该数据只有当前请求的线程可见) startTimeThreadLocal.set(startTime); String requestUri = request.getRequestURI(); UserContext loginUser = (UserContext) request.getSession().getAttribute(Constants.CURRENT_USER); if (excludeURIs.contains(requestUri)) { return true; } else { // 判断是否已经登录 Subject subject = SecurityUtils.getSubject(); String userId = (String) subject.getPrincipal(); if (StringUtil.isNotEmpty(userId)) { SysUser user = sysUserService.findByUsername(userId); // menu菜单 Set<String> permissions = sysUserService.findPermissions(user.getUsername()); List<SysResource> menus = resourceService.findByMenus(permissions); if (user != null) { UserContext userContext = new UserContext(user.getId(), user.getOrganizationId(), user.getUsername(), user.getRoleIds(), user.getLocked(), user.getRealname(), user.getSex(), user.getMobile(), user.getRoleNames(), menus,"/static/images/pixel-admin/avatar.png"); request.getSession().setAttribute(Constants.CURRENT_USER, userContext); } } UserContext loginInfo = (UserContext) request.getSession().getAttribute(Constants.CURRENT_USER); if (loginInfo == null) { response.sendRedirect(getBasePath(request) + "login.htm"); return false; } return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 统计应用的性能 // 2、结束时间 long endTime = System.currentTimeMillis(); // 得到线程绑定的局部变量(开始时间) long beginTime = startTimeThreadLocal.get(); // 3、消耗的时间 long consumeTime = endTime - beginTime; // 此处认为处理时间超过500毫秒的请求为慢请求 if(consumeTime > 500) { //TODO 记录到日志文件 logger.warn("监控==========================: " + String.format("%s consume %d millis", request.getRequestURI(), consumeTime)); } } private boolean contains(Set<String> sets, String key) { boolean result = false; if (sets != null && sets.size() > 0) { for (String s : sets) { if (s.indexOf(key) != -1) { result = true; break; } } } return result; } private String getBasePath(HttpServletRequest request) { int port = request.getServerPort(); return request.getScheme() + "://" + request.getServerName() + ((port == 80) ? "" : (":" + port)) + request.getContextPath() + "/"; } public Set<String> getExcludeURIs() { return excludeURIs; } public void setExcludeURIs(Set<String> excludeURIs) { this.excludeURIs = excludeURIs; } }
相关文章
- Spring - Netty (整合)
- web.xml中的contextConfigLocation在spring中的作用
- 使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控--转
- idea实现spring + springMVC + mybatis 整合(2)
- 注意:Spring Boot 2.7开始spring.factories不推荐使用了,接下来这么玩...
- Spring Boot 2.5.0 重新设计的spring.sql.init 配置有啥用?
- spring计划任务,springMvc计划任务,Spring@Scheduled,spring定时任务
- Spring整合CXF步骤,Spring实现webService,spring整合WebService
- Spring Boot 对多线程支持-提高程序执行效率
- 无意间做了个 web 版的 JVM 监控端(前后端分离 React+Spring Boot)
- Spring Boot filter
- Spring MVC 学习笔记 spring mvc Schema-based configuration
- spring框架漏洞整理(Spring Framework漏洞)
- Spring Boot—21Actuator--监控
- Spring Security 工作原理 (四)
- 【转】Spring学习---为什么要用spring,springMVC
- [转]Spring Boot——2分钟构建spring web mvc REST风格HelloWorld
- 谷粒学院——Day18【权限管理Spring Security、配置中心Nacos、代码托管git】
- tomcat使用spring-loaded实现应用热部署
- Java开发 - 单点登录初体验(Spring Security + JWT)
- spring boot面试问题集锦
- 如何做自己的服务监控?spring boot 2.x服务监控揭秘
- 如何做自己的服务监控?spring boot 1.x服务监控揭秘
- 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享
- 曹工说Tomcat4:利用 Digester 手撸一个轻量的 Spring IOC容器
- spring boot不要放在tomcat下启动,因为自身就带了集成tomcat