Hibernate (с поддержкой Spring) 
  Предоставить статистику Hibernate с помощью JMX довольно просто , однако при использовании JPA API для получения базового SessionFactory требуются некоторые неприятные обходные пути. 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | classJmxLocalContainerEntityManagerFactoryBean() extendsLocalContainerEntityManagerFactoryBean { overridedefcreateNativeEntityManagerFactory() ={  valmanagerFactory =super.createNativeEntityManagerFactory()  registerStatisticsMBean(managerFactory)  managerFactory } defregisterStatisticsMBean(managerFactory:EntityManagerFactory) {  managerFactory match{   caseimpl:EntityManagerFactoryImpl =>    valmBean =newStatisticsService();    mBean.setStatisticsEnabled(true)    mBean.setSessionFactory(impl.getSessionFactory);    valname =newObjectName("org.hibernate:type=Statistics,application=spring-pitfalls")    ManagementFactory.getPlatformMBeanServer.registerMBean(mBean, name);   case_=>  } }} | 
  Обратите внимание, что я создал подкласс встроенного в Springs LocalContainerEntityManagerFactoryBean .  Переопределив createNativeEntityManagerFactory() я могу получить доступ к EntityManagerFactory и попытаться org.hibernate.ejb.EntityManagerFactoryImpl его до org.hibernate.ejb.EntityManagerFactoryImpl мы смогли зарегистрировать Hibernate Mbean. 
  Еще одна вещь ушла.  Очевидно, что мы должны использовать наш собственный подкласс вместо org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean .  Кроме того, чтобы собирать фактическую статистику вместо того, чтобы просто видеть нули до конца, мы должны установить флаг hibernate.generate_statistics . 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | @BeandefentityManagerFactoryBean() ={ valentityManagerFactoryBean =newJmxLocalContainerEntityManagerFactoryBean() entityManagerFactoryBean.setDataSource(dataSource()) entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter()) entityManagerFactoryBean.setPackagesToScan("com.blogspot.nurkiewicz") entityManagerFactoryBean.setJpaPropertyMap(  Map(   "hibernate.hbm2ddl.auto"-> "create",   "hibernate.format_sql"-> "true",   "hibernate.ejb.naming_strategy"-> classOf[ImprovedNamingStrategy].getName,   "hibernate.generate_statistics"-> true.toString  ).asJava ) entityManagerFactoryBean} | 
Вот пример того, что мы можем увидеть в JvisualVM (не забудьте установить все плагины!):
Кроме того, мы получаем хорошую запись в Hibernate:
| 1 | HQL: select generatedAlias0 from Book as generatedAlias0, time: 10ms, rows: 20 | 
Ehcache
  Мониторинг кэшей очень важен, особенно в приложениях, где вы ожидаете, что значения обычно присутствуют там.  Я склонен запрашивать базу данных так часто, как это необходимо, чтобы избежать ненужных аргументов метода или локального кэширования .  Все, чтобы сделать код максимально простым.  Однако этот подход работает только тогда, когда кэширование на уровне базы данных работает правильно.  Как и в Hibernate, включение мониторинга JMX в EhCache является двухэтапным процессом.  Сначала вам нужно выставить предоставленный MBean в MBeanServer : 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 | @Bean(initMethod ="init", destroyMethod ="dispose")defmanagementService =newManagementService(ehCacheManager(), platformMBeanServer(), true, true, true, true, true)@Bean defplatformMBeanServer() =ManagementFactory.getPlatformMBeanServerdefehCacheManager() =ehCacheManagerFactoryBean.getObject@Bean defehCacheManagerFactoryBean ={ valehCacheManagerFactoryBean =newEhCacheManagerFactoryBean ehCacheManagerFactoryBean.setShared(true) ehCacheManagerFactoryBean.setCacheManagerName("spring-pitfalls") ehCacheManagerFactoryBean} | 
  Обратите внимание, что я явно установил имя CacheManager .  Это не обязательно, но это имя используется как часть имени Mbean, а имя по умолчанию содержит значение hashCode , что не очень приятно.  Последний штрих — включить статистику на основе кеша: 
| 1 2 3 4 5 6 7 8 9 | <cachename="org.hibernate.cache.StandardQueryCache"    maxElementsInMemory="10000"    eternal="false"    timeToIdleSeconds="3600"    timeToLiveSeconds="600"    overflowToDisk="false"    memoryStoreEvictionPolicy="LRU"    statistics="true"/> | 
Теперь мы можем с радостью отслеживать различные характеристики кэширования каждого кэша в отдельности:
Как мы видим, процент пропусков кэша увеличивается. Никогда хорошая вещь. Если мы не включаем статистику кэширования, включение JMX все еще является хорошей идеей, поскольку мы бесплатно получаем множество операций управления, включая очистку и очистку кэшей (полезно при отладке и тестировании).
Кварцевый планировщик
По моему скромному мнению, планировщик Quartz — очень недооцененная библиотека, но я напишу статью об этом самостоятельно. На этот раз мы только научимся контролировать его через JMX. К счастью, это так же просто, как добавить:
| 1 | org.quartz.scheduler.jmx.export=true | 
  В файл quartz.properties .  Поддержка JMX в Quartz могла бы быть немного шире, но все же можно запросить, например, какие задания выполняются в данный момент.  Кстати, новая основная версия Quartz (2.x) предлагает очень хорошую DSL-подобную поддержку планирования: 
| 1 2 3 4 5 6 7 8 9 | valjob =newJob(classOf[MyJob])valtrigger =newTrigger().  withSchedule(   repeatSecondlyForever()  ).  startAt(   futureDate(30, SECOND)  )scheduler.scheduleJob(job.build(), trigger.build()) | 
Apache Commons DBCP
Apache Commons DBCP — самая разумная библиотека пула JDBC, с которой я когда-либо сталкивался. Существует также c3p0 , но, похоже, он уже не активно развивается. Tomcat JDBC Connection Pool выглядел многообещающе, но, поскольку он входит в состав Tomcat, ваши драйверы JDBC больше не могут быть упакованы в WAR.
Единственная проблема с DBCP заключается в том, что он не поддерживает JMX. На всех (см. Этот двухлетний выпуск). К счастью, это легко обойти. Кроме того, мы узнаем, как использовать встроенную поддержку Spring JMX.
  Похоже, что стандартный BasicDataSource имеет все, что нам нужно, все, что нам нужно сделать, это представить существующие метрики через JMX.  В Spring это очень просто — просто создайте подкласс BasicDataSource и добавьте аннотацию @ManagedAttribute к нужным атрибутам: 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @ManagedResourceclassManagedBasicDataSource extendsBasicDataSource {    @ManagedAttribute overridedefgetNumActive =super.getNumActive    @ManagedAttribute overridedefgetNumIdle =super.getNumIdle    @ManagedAttribute defgetNumOpen =getNumActive + getNumIdle    @ManagedAttribute overridedefgetMaxActive:Int=super.getMaxActive    @ManagedAttribute overridedefsetMaxActive(maxActive:Int) {        super.setMaxActive(maxActive)    }    @ManagedAttribute overridedefgetMaxIdle =super.getMaxIdle    @ManagedAttribute overridedefsetMaxIdle(maxIdle:Int) {        super.setMaxIdle(maxIdle)    }    @ManagedAttribute overridedefgetMinIdle =super.getMinIdle    @ManagedAttribute overridedefsetMinIdle(minIdle:Int) {        super.setMinIdle(minIdle)    }    @ManagedAttribute overridedefgetMaxWait =super.getMaxWait    @ManagedAttribute overridedefsetMaxWait(maxWait:Long) {        super.setMaxWait(maxWait)    }    @ManagedAttribute overridedefgetUrl =super.getUrl    @ManagedAttribute overridedefgetUsername =super.getUsername} | 
Вот несколько метрик источника данных, сходящих с ума во время нагрузочного теста:
Поддержка JMX в самой среде Spring довольно проста. Как вы видели выше, предоставление произвольного атрибута или операции — это просто добавление аннотации. Вам нужно только помнить о включении поддержки JMX с использованием XML или Java (также см .: SPR-8943: аннотация, эквивалентная <context: mbean-export /> с @Configuration ):
| 1 | <context:mbean-export/> | 
или же:
| 1 | @Bean defannotationMBeanExporter() =newAnnotationMBeanExporter() | 
Эта статья не была особенно захватывающей. Однако знание метрик JMX позволит нам в кратчайшие сроки написать простые, но модные информационные панели. Будьте на связи!
Ссылка: Включение JMX в Hibernate, EhCache, Quartz, DBPC и Spring от нашего партнера по JCG Томаша Нуркевича в блоге Java и соседей .
Статьи по Теме :


