在Hibernate,EhCache,Quartz,DBCP和Spring中启用JMX
休眠(带有Spring支持)
使用JMX公开Hibernate统计信息非常简单 ,但是当使用JPA API获取基础SessionFactory
时,需要一些讨厌的解决方法
class JmxLocalContainerEntityManagerFactoryBean() extends LocalContainerEntityManagerFactoryBean { override def createNativeEntityManagerFactory() = { val managerFactory = super.createNativeEntityManagerFactory() registerStatisticsMBean(managerFactory) managerFactory } def registerStatisticsMBean(managerFactory: EntityManagerFactory) { managerFactory match { case impl: EntityManagerFactoryImpl => val mBean = new StatisticsService(); mBean.setStatisticsEnabled(true) mBean.setSessionFactory(impl.getSessionFactory); val name = new ObjectName("org.hibernate:type=Statistics,application=spring-pitfalls") ManagementFactory.getPlatformMBeanServer.registerMBean(mBean, name); case _ => } } }
请注意,我已经创建了Springs内置LocalContainerEntityManagerFactoryBean
的子类。 通过重写createNativeEntityManagerFactory()
方法,我可以访问EntityManagerFactory
并尝试将其向下转换为org.hibernate.ejb.EntityManagerFactoryImpl
我们能够注册Hibernate Mbean。
还有一件事。 显然,我们必须使用自定义子类而不是org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
。 另外,为了收集实际的统计信息,而不是一直看到零,我们必须设置hibernate.generate_statistics
标志。
@Bean def entityManagerFactoryBean() = { val entityManagerFactoryBean = new JmxLocalContainerEntityManagerFactoryBean() 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日志记录:
HQL: select generatedAlias0 from Book as generatedAlias0, time: 10ms, rows: 20
高速缓存
监视缓存非常重要,尤其是在您希望在那里通常存在值的应用程序中。 我倾向于根据需要频繁查询数据库,以避免不必要的方法参数或本地缓存 。 一切使代码尽可能简单。 但是,这种方法仅在数据库层上的缓存正常工作时才有效。 与Hibernate相似,在EhCache中启用JMX监视是一个两步过程。 首先,您需要在MBeanServer
公开提供的MBean
:
@Bean(initMethod = "init", destroyMethod = "dispose") def managementService = new ManagementService(ehCacheManager(), platformMBeanServer(), true, true, true, true, true) @Bean def platformMBeanServer() = ManagementFactory.getPlatformMBeanServer def ehCacheManager() = ehCacheManagerFactoryBean.getObject @Bean def ehCacheManagerFactoryBean = { val ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean ehCacheManagerFactoryBean.setShared(true) ehCacheManagerFactoryBean.setCacheManagerName("spring-pitfalls") ehCacheManagerFactoryBean }
请注意,我明确设置了CacheManager
名称。 这不是必需的,但是此名称用作Mbean名称的一部分,并且默认名称包含hashCode
值,这不是很好。 最后一点是启用基于缓存的统计信息:
<cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="600" overflowToDisk="false" memoryStoreEvictionPolicy="LRU" statistics="true" />
现在,我们可以愉快地分别监视每个缓存的各种缓存特征:
如我们所见,缓存未命中的百分比增加了。 从来没有一件好事。 如果我们不启用缓存统计信息,那么启用JMX仍然是一个好主意,因为我们免费获得了许多管理操作,包括刷新和清除缓存(在调试和测试过程中很有用)。
石英调度器
以我的拙见, Quartz Scheduler是一个被低估的库,但是我将自己撰写一篇有关它的文章。 这次,我们将仅学习如何通过JMX对其进行监视。 幸运的是,它就像添加一样简单:
org.quartz.scheduler.jmx.export=true
到quartz.properties
文件。 Quartz中对JMX的支持可能会稍微扩大一点,但是仍然可以查询例如当前正在运行的作业。 顺便说一下,新的主要版本的Quartz(2.x)带来了非常好的DSL类似的调度支持:
val job = newJob(classOf[MyJob]) val trigger = newTrigger(). withSchedule( repeatSecondlyForever() ). startAt( futureDate(30, SECOND) ) scheduler.scheduleJob(job.build(), trigger.build())
Apache Commons DBCP
Apache Commons DBCP是我遇到的最合理的JDBC池库。 还有c3p0 ,但似乎不再积极开发了。 Tomcat JDBC连接池看起来很有前途,但是由于它捆绑在Tomcat中,因此您的JDBC驱动程序不能再打包在WAR中。
DBCP的唯一问题是它不支持JMX。 完全没有(请参见此两年半的旧版 )。 幸运的是,这很容易解决。 此外,我们还将学习如何使用Spring内置的JMX支持。
看起来标准的BasicDataSource
拥有我们所需的全部,我们要做的就是通过JMX公开现有的指标。 使用Spring时,它简直就是简单–只需@ManagedAttribute
子类,然后在所需的属性上添加@ManagedAttribute
批注:
@ManagedResource class ManagedBasicDataSource extends BasicDataSource { @ManagedAttribute override def getNumActive = super.getNumActive @ManagedAttribute override def getNumIdle = super.getNumIdle @ManagedAttribute def getNumOpen = getNumActive + getNumIdle @ManagedAttribute override def getMaxActive: Int= super.getMaxActive @ManagedAttribute override def setMaxActive(maxActive: Int) { super.setMaxActive(maxActive) } @ManagedAttribute override def getMaxIdle = super.getMaxIdle @ManagedAttribute override def setMaxIdle(maxIdle: Int) { super.setMaxIdle(maxIdle) } @ManagedAttribute override def getMinIdle = super.getMinIdle @ManagedAttribute override def setMinIdle(minIdle: Int) { super.setMinIdle(minIdle) } @ManagedAttribute override def getMaxWait = super.getMaxWait @ManagedAttribute override def setMaxWait(maxWait: Long) { super.setMaxWait(maxWait) } @ManagedAttribute override def getUrl = super.getUrl @ManagedAttribute override def getUsername = super.getUsername }
以下是一些在负载测试期间疯狂的数据源指标:
Spring框架本身对JMX的支持非常简单。 如您所见,公开任意属性或操作只是添加注释的问题。 您只需要记住有关使用XML或Java启用JMX支持的方法(另请参见: SPR-8943:等效于<context:mbean-export />的@Configuration ):
<context:mbean-export/>
要么:
@Bean def annotationMBeanExporter() = new AnnotationMBeanExporter()
这篇文章并不特别令人兴奋。 但是,对JMX指标的了解将使我们能够立即编写简单而精致的仪表板。 敬请关注!
参考: Java和社区博客上的JCG合作伙伴 Tomasz Nurkiewicz提供了在Hibernate,EhCache,Quartz,DBPC和Spring中启用JMX的信息 。
相关文章 :
翻译自: https://www.javacodegeeks.com/2012/01/enabling-jmx-in-hibernate-ehcache-qurtz.html