Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Tomcat中使用Spring通过JMX公开Hibernate(缓存)统计信息_Hibernate_Spring_Jpa_Jmx_Ehcache - Fatal编程技术网

在Tomcat中使用Spring通过JMX公开Hibernate(缓存)统计信息

在Tomcat中使用Spring通过JMX公开Hibernate(缓存)统计信息,hibernate,spring,jpa,jmx,ehcache,Hibernate,Spring,Jpa,Jmx,Ehcache,在基于Spring的设置中收集Hibernate/Ehcache统计数据并通过JMX公开它们似乎很容易。互联网上有很多有用的资源 然而,所有这些文章都假设您正在使用某种Hibernate会话工厂。我不是-我的实体是JPA注释的,我使用javax.persistence.EntityManager。 如果我部署到一个JavaEE容器,我可能已经能够通过JNDI获得一个Hibernate会话工厂,如这里所述,但我使用的是Tomcat 怎么办?我还没有想出解决办法 如果我参考了EhcacheCache

在基于Spring的设置中收集Hibernate/Ehcache统计数据并通过JMX公开它们似乎很容易。互联网上有很多有用的资源

然而,所有这些文章都假设您正在使用某种Hibernate会话工厂。我不是-我的实体是JPA注释的,我使用
javax.persistence.EntityManager
。 如果我部署到一个JavaEE容器,我可能已经能够通过JNDI获得一个Hibernate会话工厂,如这里所述,但我使用的是Tomcat

怎么办?我还没有想出解决办法

如果我参考了Ehcache
CacheManager
,我可以尝试以下方法:

<context:mbean-server />
<bean class="net.sf.ehcache.management.ManagementService" init-method="init">
  <constructor-arg ref="..myCacheManager.."/>
  <constructor-arg ref="mbeanServer"/>
  <constructor-arg value="true"/>
  <constructor-arg value="true"/>
  <constructor-arg value="true"/>
  <constructor-arg value="true"/>
</bean>

因为缓存管理器是由Hibernate创建的(也就是说,它不是Springbean),所以它不会工作。我试着用

<constructor-arg><bean id="cacheManager" class="net.sf.ehcache.CacheManager" factory-method="getInstance"/></constructor-arg>


希望我能抓住正确的机会。也不起作用,因为这实际上会创建一个新的缓存管理器实例。

Spring仅在JMX上公开其bean,但您可以通过MBeanExporter以编程方式导出资源。

JPA EntityManager公开底层Hibernate会话,因此您可以在其工厂获得:

   public static Session getHibernateSession(EntityManager entityManager) {
        Session session;
        if (entityManager.getDelegate() instanceof EntityManagerImpl) {
            EntityManagerImpl entityManagerImpl = (EntityManagerImpl) entityManager.getDelegate();
            session = entityManagerImpl.getSession();
        } else {
            session = (Session) entityManager.getDelegate();
        }

        return session;
    }

然后,您可以使用此会话,就像我们在

中所做的那样。我最近构建了一个基于Spring的示例webapp,它非常干净地为最新版本的Spring、Hibernate和Ehcache启用JMX

它有基于EntityManager的访问和DAO访问(包括事务!)的示例。它还展示了如何进行基于注释的注入,以避免使用Spring的XMLConfigforBean。甚至还有一个使用注释的基于SpringMVC的示例servlet。基本上,这是运行在任何servlet引擎之上的相当强大的应用服务器的基于Spring的版本

它还没有被记录下来,但我很快就会开始。看看配置文件和源代码,应该很清楚

这背后的动机是,我厌倦了所有疯狂的博客文章,有50种不同的方式来设置东西,最后制作了一个简单的资源,人们可以从中工作。它在github上,所以您可以自由地进行项目,并用它做任何您想做的事情


我最后写了下面的课程

HibernateStatisticsjmx注册

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.persistence.EntityManagerFactory;

import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.jmx.StatisticsService;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Provides code to register Hibernate's statistics bean with a JMX MBean server. Assumes that both
 * the MBeanServer and the EntityManagerFactory are available as Spring-managed beans. Note that
 * while registering this class enables the collection of statistics even if that was previously
 * disabled.
 * <p>
 * May become obsolete once <a href="https://hibernate.onjira.com/browse/HHH-6034">HHH-6034</a> is
 * implemented. Even if not the confusing situation abround the meanwhile deprecated
 * {@link StatisticsService} should be clear then.
 */
@SuppressWarnings({"deprecation", "javadoc" })
public class HibernateStatisticsJmxRegistration {

  @Autowired
  private EntityManagerFactory entityManagerFactory;

  @Autowired
  private MBeanServer mbeanServer;

  private ObjectName objectName;

  private String jmxObjectName = "org.hibernate:name=HibernateStatistics";

  /**
   * Registers the statistics MBean that wraps a Hibernate session factory. The bean is registered
   * under the name provided by {@link HibernateStatisticsJmxRegistration#getJmxObjectName()}.
   *
   * @throws JMException if anything fails..
   * @see HibernateStatisticsJmxRegistration#unregister()
   */
  public void register() throws JMException {
    final SessionFactory sessionFactory = ((HibernateEntityManagerFactory) entityManagerFactory).getSessionFactory();

    objectName = new ObjectName(jmxObjectName);

    final StatisticsService statsMBean = new StatisticsService();
    statsMBean.setSessionFactory(sessionFactory);
    statsMBean.setStatisticsEnabled(true);
    mbeanServer.registerMBean(statsMBean, objectName);
  }

  /**
   * Unregisters the MBean that was registered.
   *
   * @throws JMException if the de-registration fails
   * @see HibernateStatisticsJmxRegistration#register()
   */
  public void unregister() throws JMException {
    mbeanServer.unregisterMBean(objectName);
  }

  /**
   * Override the default JMX object name. Obviously you need to call this method before
   * registration for it to have any effect. The string must comply to the rules described in
   * {@link ObjectName}. Suggested is {@code <domain>:name=<name>}.
   *
   * @param jmxObjectName the name to use during registration
   */
  public void setJmxObjectName(String jmxObjectName) {
    this.jmxObjectName = jmxObjectName;
  }
}
import javax.management.JMException;
导入javax.management.MBeanServer;
导入javax.management.ObjectName;
导入javax.persistence.EntityManagerFactory;
导入org.hibernate.SessionFactory;
导入org.hibernate.ejb.HibernateEntityManagerFactory;
导入org.hibernate.jmx.StatisticsService;
导入org.springframework.beans.factory.annotation.Autowired;
/**
*提供向JMX MBean服务器注册Hibernate的统计bean的代码。假设两者
*MBeanServer和EntityManagerFactory作为Spring管理的bean提供。注意
*注册该类时,即使以前是这样,也可以收集统计信息
*残疾人。
*
*一旦被淘汰,就可能被淘汰
*执行。即使不是令人困惑的情况,也有人反对
*{@link StatisticsService}应该是清晰的。
*/
@SuppressWarnings({“弃用”、“javadoc”})
公共类房地产登记{
@自动连线
私人实体管理工厂实体管理工厂;
@自动连线
专用MBeanServer MBeanServer;
私有ObjectName ObjectName;
私有字符串jmxObjectName=“org.hibernate:name=HibernateStatistics”;
/**
*注册包装Hibernate会话工厂的统计MBean
*在{@link hibernatestisticsjmxRegistration#getJmxObjectName()}提供的名称下。
*
*@如果出现任何故障,都会抛出异常。。
*@请参阅HibernateStatisticsJmxRegistration#unregister()
*/
public void register()引发异常{
最终SessionFactory SessionFactory=((HibernateEntityManagerFactory)entityManagerFactory).getSessionFactory();
objectName=新的objectName(jmxObjectName);
最终统计服务statsMBean=新统计服务();
statsMBean.setSessionFactory(会话工厂);
statsMBean.setStatisticsEnabled(真);
registerMBean(statsMBean,objectName);
}
/**
*注销已注册的MBean。
*
*@如果取消注册失败,将引发JMException
*@请参阅HibernateStatisticsJmxRegistration#register()
*/
public void unregister()引发异常{
mbeanServer.unregisterMBean(objectName);
}
/**
*重写默认的JMX对象名。显然,您需要先调用此方法
*要使其生效,请注册。字符串必须符合中描述的规则
*{@link ObjectName}。建议的是{@code:name=}。
*
*@param jmxObjectName注册期间要使用的名称
*/
public void setJmxObjectName(字符串jmxObjectName){
this.jmxObjectName=jmxObjectName;
}
}
弹簧配置

<!-- Setting up Ehcache manager for various caches (offer facade, images). -->
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
  <property name="configLocation" value="classpath:ehcache.xml" />
</bean>  
<ehcache:annotation-driven cache-manager="ehCacheManager" />

<!-- Exposing cache statistics through JMX. -->
<context:mbean-server />
<bean class="net.sf.ehcache.management.ManagementService" init-method="init">
  <constructor-arg ref="ehCacheManager"/>
  <constructor-arg ref="mbeanServer"/>
  <constructor-arg value="true"/>
  <constructor-arg value="true"/>
  <constructor-arg value="true"/>
  <constructor-arg value="true"/>
</bean>    
<bean class="HibernateStatisticsJmxRegistration"
      init-method="register" destroy-method="unregister" />

您实际上可以使用公开任何CacheManager


其中CACHE_NAME是在ehcache.xml文件中配置的缓存的名称

<ehcache name="CACHE_NAME">
    ...
</ehcache>

...

非常糟糕,但这也行得通,其中(猜猜看)mbeanServer是MBean服务器的bean名称,entityManagerFactory是entityManagerFactory的bean名称:

<bean id="managementService-ehcache-hibernate"
    class="net.sf.ehcache.management.ManagementService"
    init-method="init"
    destroy-method="dispose">

    <constructor-arg value="#{T(org.springframework.security.util.FieldUtils).getFieldValue(@entityManagerFactory.cache.unwrap(T(org.hibernate.cache.spi.RegionFactory)),'manager')}"/>
    <constructor-arg ref="mbeanServer"/>
    <constructor-arg index="2" value="true"/>
    <constructor-arg index="3" value="true"/>
    <constructor-arg index="4" value="true"/>
    <constructor-arg index="5" value="true"/>
</bean>


您使用的是什么版本的EhCache?我在
CacheManager
@skaffman上没有看到
getInstance()
方法,它在ehcache core 2.3.1中。是的,我知道,但我试图避免为此添加自定义代码。你的hibernate SessionFactory是一个Spring bean?是的,我可以这样做。然而,在理想情况下,它应该以声明的方式完成。-1因为费心将近60个第三方LIB上传到github,这是多么浪费资源啊。缺点
<bean id="managementService-ehcache-hibernate"
    class="net.sf.ehcache.management.ManagementService"
    init-method="init"
    destroy-method="dispose">

    <constructor-arg value="#{T(org.springframework.security.util.FieldUtils).getFieldValue(@entityManagerFactory.cache.unwrap(T(org.hibernate.cache.spi.RegionFactory)),'manager')}"/>
    <constructor-arg ref="mbeanServer"/>
    <constructor-arg index="2" value="true"/>
    <constructor-arg index="3" value="true"/>
    <constructor-arg index="4" value="true"/>
    <constructor-arg index="5" value="true"/>
</bean>