Привет, в моей предыдущей статье я объяснил, как настроить сервер JMX через Spring и как защитить доступ к нему через аутентификацию и авторизацию.
В этой статье я покажу, как реализовать простой MBean, который позволяет пользователям изменять уровень регистратора Log4j во время выполнения без необходимости перезапуска приложения.
Конфигурация Spring немного изменилась по сравнению с моей предыдущей статьей для облегчения тестирования; вещество остается тем же.
Конфигурация Spring
| 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <?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"    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 fortesting -->    <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 регистрируются на сервере JMX как MBeans)
LoggerConfigurator MBean
| 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | packageuk.co.jemos.experiments.jmx.mbeans;importorg.apache.log4j.Level;importorg.apache.log4j.Logger;importorg.springframework.jmx.export.annotation.ManagedOperation;importorg.springframework.jmx.export.annotation.ManagedOperationParameter;importorg.springframework.jmx.export.annotation.ManagedOperationParameters;importorg.springframework.jmx.export.annotation.ManagedResource;importorg.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")publicclassLoggerConfigurator {        publicstaticfinalString 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"), })    publicString getLoggerLevel(String loggerName) {        Logger logger = Logger.getLogger(loggerName);        Level loggerLevel = logger.getLevel();        returnloggerLevel == 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") })    publicvoidsetLoggerLevel(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. Однако с этими аннотациями мы сделали MBean, и этот компонент будет зарегистрирован на сервере JMX при запуске.
Аннотации @ManagedOperation и @ManagedOperationParameters определяют, что будет отображаться в jconsole. Можно было бы опустить эти аннотации, но имена параметров не стали бы чем-то вроде p1 и p2, не давая никакой информации о типе параметра.
Вызов функции, скажем, со значением foo.bar.baz, INFO приведет к следующему выводу:
| 1 2 3 | ...snip2011-08-11 21:33:36 LoggerConfigurator [INFO] Set logger foo.bar.baz to level INFO | 
В моей следующей и последней статье для этой серии я покажу, как настроить MBean, который оповещает слушателя о достижении порога памяти HEAP, как объяснялось в одной из моих предыдущих статей.
Продолжайте к части 3 .
Ссылка: JMX и Spring — часть 2 от нашего партнера по JCG
