如何计算Spring MVC中JSP模板的渲染耗时?
计算Spring MVC中JSP模板渲染耗时的可行方案
当然有靠谱的办法!针对Spring MVC搭配JSP开发的场景,我给你几个精准计算JSP模板渲染耗时的方案,都是实际项目里验证过的,完全能满足你只关注模板渲染阶段的需求:
方案1:JSP页面内直接埋点(快速验证用)
这个方案最直接,适合临时验证单个页面的渲染耗时,不需要修改后端代码:
- 在JSP的最顶部(页面指令
<%@ page ... %>之后)添加时间戳记录:<% long renderStart = System.currentTimeMillis(); %> - 在JSP的最末尾(所有页面内容结束后)计算耗时并输出/记录:
<% long renderEnd = System.currentTimeMillis(); long renderTime = renderEnd - renderStart; // 可以用日志框架输出,比如SLF4J // org.slf4j.LoggerFactory.getLogger(getClass()).info("当前JSP渲染耗时:{}ms", renderTime); // 或者简单打印到控制台 System.out.println("JSP [" + request.getRequestURI() + "] 渲染耗时:" + renderTime + "ms"); %> - 优点:零后端代码修改,快速上手;缺点:需要给每个要监控的JSP手动加代码,维护成本高,嵌套
include的页面如果也加埋点会重复计算。
方案2:扩展Spring的InternalResourceView(全局统一监控)
Spring MVC默认用InternalResourceView处理JSP视图,我们可以继承这个类,重写渲染方法来全局监控所有JSP的耗时:
- 自定义View类:
import org.springframework.web.servlet.view.InternalResourceView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; public class TimedInternalResourceView extends InternalResourceView { private static final Logger logger = LoggerFactory.getLogger(TimedInternalResourceView.class); @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { long start = System.currentTimeMillis(); // 调用父类的渲染逻辑,也就是实际的JSP渲染 super.renderMergedOutputModel(model, request, response); long end = System.currentTimeMillis(); // 获取视图名称(优先取BeanName,没有的话取URL) String viewName = getBeanName() != null ? getBeanName() : getUrl(); logger.info("JSP视图 [{}] 渲染耗时:{}ms", viewName, end - start); } } - 配置视图解析器使用自定义View:
- 如果是XML配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="com.yourpackage.TimedInternalResourceView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> - 如果是Java配置:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration public class WebMvcConfig { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(TimedInternalResourceView.class); resolver.setPrefix("/WEB-INF/jsp/"); resolver.setSuffix(".jsp"); return resolver; } }
- 如果是XML配置:
- 优点:全局生效,所有JSP的渲染耗时自动记录,不需要修改任何JSP;缺点:需要自定义View类,对Spring MVC视图机制有一点基础认知。
方案3:Spring AOP拦截渲染方法(解耦式监控)
如果不想修改View类,用AOP切面来拦截JSP渲染的核心方法,实现解耦式的耗时监控:
- 编写切面类:
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import org.springframework.web.servlet.view.InternalResourceView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Aspect @Component public class JspRenderTimeAspect { private static final Logger logger = LoggerFactory.getLogger(JspRenderTimeAspect.class); // 拦截InternalResourceView的renderMergedOutputModel方法 @Around("execution(* org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(..))") public Object recordRenderTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); // 执行原有的渲染逻辑 Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); // 获取当前视图对象 InternalResourceView view = (InternalResourceView) joinPoint.getTarget(); String viewName = view.getBeanName() != null ? view.getBeanName() : view.getUrl(); logger.info("JSP视图 [{}] 渲染耗时:{}ms", viewName, end - start); return result; } } - 开启Spring AOP支持:在你的Spring配置类上添加
@EnableAspectJAutoProxy注解。
- 优点:完全解耦,不需要修改View类和JSP,全局监控;缺点:需要熟悉AOP语法,确保切面能覆盖所有JSP视图的渲染方法。
注意事项
- 以上方案计算的都是服务器端JSP生成HTML的时间,不包含浏览器请求静态资源(图片、CSS、JS)的时间,正好符合你只关注模板渲染阶段的需求。
- 如果用日志记录耗时,建议用SLF4J+Logback/Log4j2这类成熟的日志框架,方便后续分析。
内容的提问来源于stack exchange,提问作者Sabrina
相关产品推荐
相关产品推荐

