`
carlosfu
  • 浏览: 582314 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Ba8b5055-9c58-3ab0-8a1c-e710f0495d2c
BigMemory实战与理...
浏览量:31216
53b2087e-c637-34d2-b61d-257846f73ade
RedisCluster开...
浏览量:151027
C9f66038-7478-3388-8086-d20c1f535495
缓存的使用与设计
浏览量:125220
社区版块
存档分类
最新评论

利用Jmx统计spring-mvc所有controller的调用

阅读更多

 

转载请注明出处哈:http://carlosfu.iteye.com/blog/2240426


 

      一、spring-mvc添加拦截器配置: 对所有/下的访问都做拦截

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.sohu.tv.mobil.web.interceptor.VisitCounterStatInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

 

   二、 定义VisitCounterStatInterceptor

  

  1. 这里我们使用了guava的中的AtomicLongMap, 它的底层是ConcurrentHashMap<String,Long>,可以用来记录每个key的counter, 可以作为一种很高效的计数器。

  2. 这里我们用定义了两个AtomicLongMap, 分别记录每个controller-uri对应的访问次数以及慢查询次数(例如超过100秒)。 

  3. 耗时是通过ThreadLocal来记录,在preHandle记录开始时间,在afterCompletion计算整个controller的耗时,但是这里强调一下finally中一定要调用costThreadLocal.remove();

package com.sohu.tv.mobil.web.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.google.common.util.concurrent.AtomicLongMap;

/**
 * 访问相关统计拦截器
 * 
 * @author leifu
 * @Date 2015年10月30日
 * @Time 上午9:36:16
 */
public class VisitCounterStatInterceptor extends HandlerInterceptorAdapter {
    private Logger logger = LoggerFactory.getLogger(VisitCounterStatInterceptor.class);

    /**
     * 记录接口访问
     */
    public static final AtomicLongMap<String> VISIT_COUNT_MAP = AtomicLongMap.create();

    /**
     * 记录接口慢查询
     */
    public static final AtomicLongMap<String> VISIT_SLOW_COST_MAP = AtomicLongMap.create();

    /**
     * 耗时
     */
    private ThreadLocal<Long> costThreadLocal = new ThreadLocal<Long>();

    /**
     * 最大接受的耗时
     */
    private final static long MAX_ACCEPT_TIME = 100;

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();
        if (StringUtils.isNotBlank(uri)) {
            VISIT_COUNT_MAP.incrementAndGet(uri);
            // 记录startTime
            costThreadLocal.set(System.currentTimeMillis());
        }
        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 {
        try {
            String uri = request.getRequestURI();
            if (StringUtils.isNotBlank(uri)) {
                long startTime = costThreadLocal.get();
                long costTime = System.currentTimeMillis() - startTime;
                if (costTime > MAX_ACCEPT_TIME) {
                    VISIT_SLOW_COST_MAP.incrementAndGet(uri);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            costThreadLocal.remove();
        }
    }
}

 

  三、利用jmx记录controller-uri的调用统计

 

  1. 定义MBean:

package com.sohu.tv.mobil.common.jmx;

import java.util.Map;

public interface CounterMapMBean {

    void clear();

    Map<String,Long> getCounterMap();

}

 

  2.定义MBean的实现:

package com.sohu.tv.mobil.common.jmx.impl;

import com.google.common.util.concurrent.AtomicLongMap;
import com.sohu.tv.mobil.common.jmx.CounterMapMBean;

import java.util.*;

public class CounterMapImpl implements CounterMapMBean {

    public final AtomicLongMap<String> counterMap;

    public CounterMapImpl(AtomicLongMap<String> counterMap) {
        this.counterMap = counterMap;
    }

    @Override
    public void clear() {
        counterMap.clear();
    }

    @Override
    public Map<String, Long> getCounterMap() {
        List<Map.Entry<String, Long>> entryList = new ArrayList<>(counterMap.asMap().entrySet());
        Collections.sort(entryList, new Comparator<Map.Entry<String, Long>>() {
            @Override
            public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) {
                Long v1 = o1.getValue();
                Long v2 = o2.getValue();
                if (v1 > v2) {
                    return -1;
                } else if (v1 < v2) {
                    return 1;
                } else {
                    return o1.getKey().compareTo(o2.getKey());
                }
            }
        });
        Map<String, Long> resultMap = new LinkedHashMap<String, Long>();
        for (Map.Entry<String, Long> entry : entryList) {
            resultMap.put(entry.getKey(), entry.getValue());
        }
        return resultMap;
    }

}

 

  3. 在spring中定义jmx:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
       default-autowire="byName">

    <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
        <property name="locateExistingServerIfPossible" value="true"/>
    </bean>

    <bean id="visitCounterMap" class="com.sohu.tv.mobil.common.jmx.impl.CounterMapImpl">
        <constructor-arg index="0">
            <util:constant static-field="com.sohu.tv.mobil.web.interceptor.VisitCounterStatInterceptor.VISIT_COUNT_MAP"/>
        </constructor-arg>
    </bean>
    
    <bean id="visitSlowCostMap" class="com.sohu.tv.mobil.common.jmx.impl.CounterMapImpl">
        <constructor-arg index="0">
            <util:constant static-field="com.sohu.tv.mobil.web.interceptor.VisitCounterStatInterceptor.VISIT_SLOW_COST_MAP"/>
        </constructor-arg>
    </bean>

    <bean id="mBeanServer" class="org.springframework.jmx.export.MBeanExporter">
        <property name="beans">
            <map>
                <entry key="mobilJMX:myjavaobj=visitCounterMap" value-ref="visitCounterMap"/>
                <entry key="mobilJMX:myjavaobj=visitSlowCostMap" value-ref="visitSlowCostMap"/>
            </map>
        </property>
        <property name="server" ref="mbeanServer"/>
        <property name="assembler" ref="assembler"/>
    </bean>

    <bean id="assembler"
          class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
        <property name="managedInterfaces">
            <list>
                <value>com.sohu.tv.mobil.common.jmx.CounterMapMBean</value>
            </list>
        </property>
    </bean>

</beans>

  

  4. 上线后,就可以在jvisualvm或者jconsole中看到MBean的调用统计:

  

  5. 我们在后台,调用jmx,并做成界面:

  

   

  四、 存在的几个问题

 

  1. request.getRequestURI()可能会存在问题,比如如果使用了如下配置,可能会撑爆AtomicLongMap, 造成内存溢出,解决方法还要进一步观察(但是暂时我们的系统没有使用这种调用方式)

    @RequestMapping(value = "/drama/{pid}", produces = "text/javascript; charset=UTF-8")
  

  2. 使用了<mvc:mapping path="/**"/>后,出现了很多奇怪的uri, 比如下图中的情况,具体原因还要查询。

   

 

  3. jmx是非持久化的,只能查询实时数据,如果需要的话可以定期统计jmx到mysql或者其他存储,方便查询历史数据,帮助有效定位问题

  

  4. jmx的数据可以结合nagios或者ganglia来使用,不需要单独开发后台界面。

 

 附图一张:

 

 

  • 大小: 51.6 KB
  • 大小: 29.1 KB
  • 大小: 18.6 KB
  • 大小: 639.9 KB
分享到:
评论

相关推荐

    spring mvc jar包

    3. `org.springframework.web.servlet-3.0.2.RELEASE.jar`:这是 Spring MVC 的核心模块,提供了控制器(Controller)、模型视图(ModelAndView)以及调度器Servlet(DispatcherServlet)等关键组件。...

    spring jar 包详解

    MVC(Model-View-Controller)设计模式是构建动态网站的标准模式之一。`spring-webmvc.jar`实现了这一模式,提供了控制器、视图解析器、表单标签库等功能。它使得构建Web应用变得更加简单、直观。 #### spring-...

    springspring-framework-3.0.0.M2

    6. **JMX(Java Management Extensions)集成**:Spring 3.0 提供了对 JMX 的全面支持,使应用程序的管理更加便捷,可以监控和管理应用的运行状态。 7. **Spring Expression Language (SpEL)**:Spring 3.0 引入的 ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    2.5.1. Spring MVC的表单标签库 2.5.2. Spring MVC合理的默认值 2.5.3. Portlet 框架 2.6. 其他特性 2.6.1. 动态语言支持 2.6.2. JMX 2.6 .3. 任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 ...

    spring-framework-0.9.zip

    此外,Spring 0.9还包括对JMS(Java Message Service)、JMX(Java Management Extensions)以及邮件服务的支持,为企业级应用开发提供了全面的解决方案。 总结,Spring框架0.9版本虽然相比现在的高级版本在功能上...

    spring-framework-3.2.5.src.zp

    4. **MVC(Model-View-Controller)**:Spring MVC是Spring框架的一部分,用于构建Web应用程序。它提供了一个灵活的架构,将模型、视图和控制器分离,使得代码结构清晰,易于维护。在3.2.5版本中,Spring MVC引入了...

    spring-framework-3.2.4.RELEASE

    8. **JMX支持**:Spring 3.2.4提供了对Java Management Extensions(JMX)的增强支持,允许应用管理和监控。 9. **WebSocket支持**:在3.2版本中,Spring引入了对WebSocket协议的支持,以实现双向通信,提高了Web...

    Spring4.2.0_发布版lib

    7. **WebMvc**:这部分是Spring MVC,Spring的Model-View-Controller实现,是构建Web应用的主要组件。它提供了控制器、视图解析、数据绑定等功能,使开发者能够快速构建高性能的Web应用。 在Spring 4.2.0版本中,有...

    spring-four-sample:基于Spring 4框架的示例Web应用程序

    3. **MVC(Model-View-Controller)**:Spring MVC是Spring框架的一部分,用于构建Web应用程序。它提供了一种模型驱动的方式,将业务逻辑、数据展示和用户交互分离。 **Spring 4的新特性和改进** 1. **Java 8支持*...

    spring 中文 文档

    4. **Spring MVC增强**:Spring 3.0的MVC模块有了显著增强,如支持RESTful风格的Web服务,改进的模型-视图-控制器(Model-View-Controller)架构,以及强大的视图解析能力。 5. **JMX支持**:增加了对Java ...

    使用MyEclipse6开发Struts+Spring应用程序Samples Project

    这两个框架在Java企业级应用开发中占据着重要地位,Struts提供了MVC(Model-View-Controller)架构,而Spring则为依赖注入(Dependency Injection)和面向切面编程(Aspect-Oriented Programming)提供了强大支持。...

    springmvc+spring3.1.0+ibatis2.3.4相关jar包

    这个压缩包中的 jar 文件包含了 Spring MVC、Spring 和 iBATIS 的所有依赖,方便开发者快速搭建开发环境。使用这些 jar 包时,要注意版本兼容性,确保各个组件之间的协调工作。同时,随着技术的发展,现代项目更多地...

    struts-2.1.8-apps 所有最新的Struts2.x开发应用

    Struts2是一个强大的Java web应用程序框架,用于构建和管理MVC(Model-View-Controller)架构的Web应用程序。Struts2.1.8是该框架的一个特定版本,它包含了若干改进和更新,以提高开发效率和应用性能。在这个"struts...

    HIBERNATE SPRING STRUTS包

    再者,Struts是一个基于MVC(Model-View-Controller)设计模式的Web应用框架。它专注于控制层,处理HTTP请求,调用业务逻辑,然后将结果传递给视图层。Struts通过Action和ActionForm对象来处理用户请求,Action...

    spring4+springMVC+mybaits3

    标题 "spring4+springMVC+mybaits3" 提示我们关注的是Spring框架的第四版(Spring 4)与Spring MVC以及MyBatis 3的整合应用。这是一个常见的Java Web开发技术栈,用于构建高效、灵活且可扩展的企业级应用程序。 ...

    Spring架包

    3. **MVC框架**:Spring MVC是Spring提供的Web开发框架,提供了Model-View-Controller模式的实现,支持RESTful、模板引擎等多种特性。 4. **测试**:Spring Test模块提供了对单元测试和集成测试的支持,与JUnit和...

    Spring中文帮助文档

    2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持 2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态...

    我的spring参考书

    Spring还支持其他功能,如远程服务调用(RMI、Hessian、 Burlap)、邮件服务、任务调度、缓存(如 Ehcache 和 Hazelcast 集成)、JMX支持以及测试工具等。这些都为开发者提供了丰富的选择,以满足不同场景下的开发...

    Spring API

    2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持 2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态...

Global site tag (gtag.js) - Google Analytics