2014-09-30 2 views
1

Что я хотел бы сделать, это следующее: Отображение статистики вызовов (в основном количество вызовов и среднее время вызова) через JMX. Проблема в том, что я хотел бы сделать это с поддержкой AspectJ (чтобы автоматически вычислить его для моих классов реализации).Программная публикация статистики вызовов с помощью JMX

То, что я создал это JmxBean:

public class JmxStatistics implements Serializable { 

private final String name; 
private long errorCount; 
private long errorCallTime; 
private long successCount; 
private long successCallTime; 

public JmxStatistics(String name) { 
    this.name = name; 
} 

public synchronized long getCallCount() { 
    return errorCount + successCount; 
} 

public synchronized long getAvgCallTimeInMillisecs() { 
    return (errorCallTime + successCallTime)/getCallCount(); 
} 

public synchronized long getAvgSuccessfulCallTimeInMillisecs() { 
    return (errorCallTime + successCallTime)/successCount; 
} 

public synchronized long getAvgFailedCallTimeInMillisecs() { 
    return (errorCallTime + successCallTime)/errorCount; 
} 

public synchronized void increaseErrorCallTime(long sumCallTime) { 
    this.errorCallTime += sumCallTime; 
} 

public synchronized void increaseSuccessCallTime(long sumCallTime) { 
    this.successCallTime += sumCallTime; 
} 

public synchronized long getErrorCount() { 
    return errorCount; 
} 

public synchronized void incrementErrorCount() { 
    this.errorCount++; 
} 

public synchronized long getSuccessCount() { 
    return successCount; 
} 

public synchronized void incrementSuccessCount() { 
    this.successCount++; 
} 

@Override 
public String toString() { 
    return name + "{" + "callCount=" + getCallCount() 
      + " (s: " + successCount + ",e:" + errorCount + "); " 
      + "avgCallTime=" + getAvgCallTimeInMillisecs() + "ms " 
      + "(" + getAvgSuccessfulCallTimeInMillisecs() + "ms;e:" + getAvgFailedCallTimeInMillisecs() + "ms)" + "}"; 
} 

Точка АОП обертывание:

public Object wrap(ProceedingJoinPoint joinPoint) throws Throwable { 
    JmxStatistics jmxs = store.getStatisticsBean(joinPoint); 
    long start = System.currentTimeMillis(); 
    Object result; 
    try { 
     result = joinPoint.proceed(); 
    } catch (Throwable t) { 
     long runtime = System.currentTimeMillis() - start; 
     jmxs.incrementErrorCount(); 
     jmxs.increaseErrorCallTime(runtime); 
     throw t; 
    } 
    long runtime = System.currentTimeMillis() - start; 
    jmxs.incrementSuccessCount(); 
    jmxs.increaseSuccessCallTime(runtime); 
    return result; 
} 

И магазин для раскрытия всех (программно созданных) JMX бобов:

public class JmxStatisticsStore { 

private final HashMap<String, JmxStatistics> jmxBeans = new HashMap<>(); 

public HashMap<String, JmxStatistics> getJmxBeans() { 
    return jmxBeans; 
} 

JmxStatistics getStatisticsBean(ProceedingJoinPoint joinPoint) { 
    String id = joinPoint.getTarget().getClass().toString() + "." + joinPoint.getSignature().getName(); 
    if (!jmxBeans.containsKey(id)) { 
     synchronized (jmxBeans) { 
      if (!jmxBeans.containsKey(id)) { 
       JmxStatistics jmxStatistics = new JmxStatistics(id); 
       jmxBeans.put(id, jmxStatistics); 
      } 
     } 
    } 
    return jmxBeans.get(id); 
} 
} 

Я хотел бы использовать Spring AOP и MBeanExporter для этого. Моя конфигурация выглядит следующим образом:

<bean id="jmxStatisticsStore" class="package.JmxStatisticsStore"/> 
<bean id="jmxAspect" class="package.AspectJJmxCalculator" /> 
<aop:config>   
    <aop:aspect id="jmxAspectId" ref="jmxAspect"> 

     <aop:pointcut id="pointCutAround" 
         expression="execution(* jmx.tester..*.*(..))" /> 

     <aop:around method="wrap" pointcut-ref="pointCutAround" /> 
    </aop:aspect> 
</aop:config> 
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false"> 
    <property name="beans"> 
     <map> 
      <entry key="bean:name=callStatistics" value-ref="jmxStatisticsStore"/> 
     </map> 
    </property> 
</bean> 

В настоящее время я пытаюсь запустить его в котом (пакет jmx.tester пружинный компонент, который я использую в веб-приложение). Webapp работает правильно, а с JConsole я могу подключиться к серверу. На сервере, под бобами, я могу видеть компонент callStatistics с атрибутом HashMap.

До тех пор, пока я не сделаю звонок, hashmap пуст (что хорошо) (в поле «Значение» он показывает {}) После того как я сделаю звонок (так что hashmap больше не пуст) Значение становится Недоступно, и если я пытаюсь вызвать метод getJmxBeans через JMX, я получаю следующее исключение:

Problem invoking getJmxBeans: java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: package.JmxStatistics (no security manager: RMI class loader disabled) 

EDIT: Я хотел бы видеть, что вызовы для различных идентификаторов показывают, как отдельные атрибуты JMX ,

Есть ли способ сделать то, что я хочу достичь? Thx

ответ

0

удалось решить эту. Измененный JmxStatisticsStore:

@Autowired 
MBeanExporter exporter; 

private static final Logger LOG = LogManager.getLogger(); 
private final HashMap<String, Object> jmxBeans = new HashMap(); 

JmxData getStatisticsBean(ProceedingJoinPoint joinPoint) { 
    String id = "bean:name=" + joinPoint.getTarget().getClass().toString() + "." + joinPoint.getSignature().getName(); 
    if (!jmxBeans.containsKey(id)) { 
     synchronized (jmxBeans) { 
      if (!jmxBeans.containsKey(id)) { 
       JmxData jmxStatistics = new JmxData(id); 
       jmxBeans.put(id, jmxStatistics); 
       try { 
        exporter.registerManagedResource(jmxStatistics, new ObjectName(id)); 
       } catch (MalformedObjectNameException ex) { 
        LOG.warn("Error while registering " + id, ex); 
       } 
      } 
     } 
    } 
    return (JmxData) jmxBeans.get(id); 
} 

Таким образом, это создает новые MBeans во время выполнения

1

Я рекомендую вам Metrics library.

Имеет Spring integration и сообщает через JMX.

Используйте эту библиотеку в Spring очень просто, используя аннотации. Это пример;

общественный класс Foo {

@Timed 
public void bar() { /* … */ } 

public void baz() { 
    this.bar(); // doesn't pass through the proxy 

    // fix: reengineer 
    // workaround: enable `expose-proxy` and change to: 
    ((Foo) AopContext.currentProxy()).bar(); // hideous, but it works 
} 

}

+0

Хммм ... будет проверить это позже, если это лучше, чем наше текущее решение – SzaboAdam

Смежные вопросы