<This post was migrated from my wiki site, which I decided to dispose of>
I was recently tasked with the configuration of JMX monitoring of ehcache in Hibernate-backed JPA environment glued with Spring.
As you can see there are five elements here that need to be integrated into a single whole: ehcache, JMX, Hibernate, JPA, and Spring.
Having looked around, I found a fairly close shot - a blog post by Max Poon that deals with all the sought for aspects with the exception of Spring. This, as well as the fact that in the blog the action happens in NetBeans, JSF, GlassFish world rather than in my world of Eclipse, Struts, Spring, and Tomcat, prompted me to look further.
My next stop was Struts 2 tutorial. Here the speech was about Struts (expected, right?), Hibernate, JPA, and Spring. The environment felt close to home and I decided to take it as a foundation and throw in bits and pieces from Mr. Poon's blog post to arrive to the destination. Being in the "get things done" mood, I came up to a minimalistic setup with a single cached persistent entity - quickstart.model.Person - to serve as the example.
The end result in attached.
There is an Eclipse project under src/main directory that can be imported into your Eclipse-based IDE. Before doing so make sure you ran the following Maven goal:
mvn dependency:copy-dependencies
to populate target/dependency directory with the jar files.
Below are the notes for the curious.
All the Hibernate properties go into the persistence.xml file:
<persistence-unit name="punit">
<properties>
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
<property name="hibernate.cache.use_minimal_puts" value="false" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_structured_entries" value="true" />
<property name="hibernate.ejb.classcache.quickstart.model.Person" value="read-write" />
</properties>
</persistence-unit>
applicationContext.xml defines a jmxAgent bean and the beans it depends on:
<bean id="mbeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="jmxAgent" class="quickstart.util.JmxAgent" init-method="init">
<property name="mbeanServer" ref="mbeanServer" />
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
JmxAgent.java contains the MBean registration code:
public void init() throws Exception {
EntityManager entityManager = null;
SessionFactory sessionFactory = null;
try {
entityManager = entityManagerFactory.createEntityManager();
Session session = (Session) entityManager.getDelegate();
sessionFactory = session.getSessionFactory();
} finally {
if (entityManager != null) {
entityManager.close();
}
}
// Enable Hibernate JMX Statistics
ObjectName on = new ObjectName("Hibernate:type=statistics,application=quickstart");
StatisticsService statsMBean = new StatisticsService();
statsMBean.setSessionFactory(sessionFactory);
statsMBean.setStatisticsEnabled(true);
mbeanServer.registerMBean(statsMBean, on);
// Enable Ehcache JMX Statistics
CacheManager cacheMgr = CacheManager.getInstance();
ManagementService.registerMBeans(cacheMgr, mbeanServer, true, true, true, true);
}
Alternative Spring Configuration (contributed by a visitor)
<!-- Spring bean for Hibernate Statistics -->
<bean id="hibernateStatisticsMBean" class="org.hibernate.jmx.StatisticsService">
<property name="statisticsEnabled" value="true"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- Spring initialization of ehCache's mbeans -->
<bean id="ehCacheMBeanRegistration" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="net.sf.ehcache.management.ManagementService.registerMBeans"/>
<property name="arguments">
<list>
<ref bean="cacheManager"/>
<ref bean="mbeanServer"/>
<value>true</value>
<value>true</value>
<value>true</value>
<value>true</value>
</list>
</property>
</bean>
<!-- Spring JMX bean server and exporter -->
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true"/>
</bean>
<bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="category=statistics,name=hibernate" value-ref="hibernateStatisticsMBean"/>
</map>
</property>
<property name="server" ref="mbeanServer"/>
...
</bean>
<!-- Beans referenced by JMX MBeans -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
...
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache-hibernate.xml"/>
</bean>
Comment by a visitor:
To make the EHCache statistics work I had to set the shared property on the EHCacheManagerFactoryBean to true, like so:
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
1 comments:
Hello,
We have packaged EhCache JMX registration in a compact Spring XML namespace based configuration declaration :
<management:eh-cache-management-service
mbean-server="mbeanServer"
cache-manager="cacheManager" />
We also published an Hyperic HQ plugin to monitor EhCache caches (hit/miss ratio, size, etc).
Details are here.
This util is part of larger Open Source JMX/Management library we called xebia-management-extras that covers Jakarta Commons DBCP dataSource, util.concurrent ExecutorService, JMS (connection factory, Spring's DefaultMessageListenerContainer, etc), CXF and a @Profiled annotation to ease monitoring of business code.
All the details are at Google Code - Xebia Management Extras.
Hope this helps,
Cyrille
Post a Comment