嗨,在我的前一篇文章中,我解释了如何通过Spring设置JMX服务器以及如何通过身份验证和授权保护对它的访问。
在本文中,我将展示如何实现一个简单的MBean,该MBean允许用户在运行时更改Log4j记录器的级别,而无需重新启动应用程序。
为了方便测试,Spring配置与我的前一篇文章仅作了些许更改。 实质保持不变。
Spring配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jemos-jmx.properties</value>
<value>file:///${user.home}/.secure/jmxconnector-credentials.properties</value>
</list>
</property>
</bean>
<!-- In order to automatically detect MBeans we need to recognise Spring beans -->
<context:component-scan base-package="uk.co.jemos.experiments.jmx.mbeans" />
<!-- This causes MBeans annotations to be recognised and MBeans to be registered with the JMX server -->
<context:mbean-export default-domain="jemos.mbeans"/>
<bean id="jemosJmxServer" class="org.springframework.jmx.support.ConnectorServerFactoryBean"
depends-on="rmiRegistry">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"
value="service:jmx:rmi://localhost/jndi/rmi://localhost:${jemos.jmx.rmi.port}/jemosJmxConnector" />
<property name="environment">
<!-- the following is only valid when the sun jmx implementation is used -->
<map>
<entry key="jmx.remote.x.password.file" value="${user.home}/.secure/jmxremote.password" />
<entry key="jmx.remote.x.access.file" value="${user.home}/.secure/jmxremote.access" />
</map>
</property>
</bean>
<bean id="rmiRegistry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="${jemos.jmx.rmi.port}" />
</bean>
<!-- Used for testing -->
<bean id="clientConnector" class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean"
depends-on="jemosJmxServer">
<property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:${jemos.jmx.rmi.port}/jemosJmxConnector"/>
<property name="environment">
<map>
<entry key="jmx.remote.credentials">
<bean factory-method="commaDelimitedListToStringArray">
<constructor-arg value="${jmx.username},${jmx.password}" />
</bean>
</entry>
</map>
</property>
</bean>
</beans>
我们唯一感兴趣的配置部分是扫描Spring组件和MBean导出器的声明(这也会导致MBean注释被识别,Spring Bean作为MBeans向JMX服务器注册)
LoggerConfigurator MBean
package uk.co.jemos.experiments.jmx.mbeans;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
/**
* MBean which allows clients to change or retrieve the logging level for a
* Log4j Logger at runtime.
*
* @author mtedone
*
*/
@Component
@ManagedResource(objectName = LoggerConfigurator.MBEAN_NAME, //
description = "Allows clients to set the Log4j Logger level at runtime")
public class LoggerConfigurator {
public static final String MBEAN_NAME = "jemos.mbeans:type=config,name=LoggingConfiguration";
@ManagedOperation(description = "Returns the Logger LEVEL for the given logger name")
@ManagedOperationParameters({ @ManagedOperationParameter(description = "The Logger Name", name = "loggerName"), })
public String getLoggerLevel(String loggerName) {
Logger logger = Logger.getLogger(loggerName);
Level loggerLevel = logger.getLevel();
return loggerLevel == null ? "The logger " + loggerName
+ " has not level" : loggerLevel.toString();
}
@ManagedOperation(description = "Set Logger Level")
@ManagedOperationParameters({
@ManagedOperationParameter(description = "The Logger Name", name = "loggerName"),
@ManagedOperationParameter(description = "The Level to which the Logger must be set", name = "loggerLevel") })
public void setLoggerLevel(String loggerName, String loggerLevel) {
Logger thisLogger = Logger.getLogger(this.getClass());
thisLogger.setLevel(Level.INFO);
Logger logger = Logger.getLogger(loggerName);
logger.setLevel(Level.toLevel(loggerLevel, Level.INFO));
thisLogger.info("Set logger " + loggerName + " to level "
+ logger.getLevel());
}
}
除了Spring JMX注释(以粗体显示)之外,这是一个普通的Spring bean。 但是,使用这些注释,我们制作了一个MBean,并且该bean将在启动时向JMX服务器注册。
@ManagedOperation和@ManagedOperationParameters批注确定在jconsole上显示的内容。 可以省略这些注释,但是在不提供任何有关参数类型的信息的情况下,参数名称将不会变成p1和p2之类的东西。
例如,使用值foo.bar.baz和INFO调用该函数将导致以下输出:
...snip
2011-08-11 21:33:36 LoggerConfigurator [INFO] Set logger foo.bar.baz to level INFO
在本系列的下一篇和最后一篇文章中,我将展示如何设置MBean,以在达到HEAP内存阈值时向侦听器发出警报,如我以前的一篇文章中所述
继续第3部分 。
参考: JMX和Spring –我们的JCG合作伙伴 Marco Tedone的第2部分 ,位于Marco Tedone的博客博客中。
翻译自: https://www.javacodegeeks.com/2012/07/jmx-and-spring-part-2.html