Меня часто спрашивают, готов ли Grails к использованию в корпоративных приложениях. Вкратце – да. Однако обычно я отвечаю примерно так: "Да, если вы уверены, что Spring и Hibernate (технологии, на которых базируется Grails) готовы. Да, если вы считаете, что Tomcat или JBoss (или тот сервер приложений Java EE, который вы используете) готов. Да, если MySQL или PostgreSQL (или та СУБД, которую вы используете) готовы. В конце концов – да, насколько само программирование на Java отвечает потребностям корпоративных приложений".
Группа компаний British Sky Broadcasting Group недавно перевела свой внешний Web-сайт, к которому приходит до 110 миллионов обращений в месяц, на Grails. Некоторые коммерческие части сайта LinkedIn.com работают на Grails. Web-сайт Tropicana Juice в Великобритании работает на Grails уже несколько лет. Домашний сайт Grails.org написан на Grails и выдерживает нагрузку в 70,000 загрузок в месяц. Наконец, недавнее приобретение G2One (фирмы, осуществляющей поддержку Groovy и Grails) компанией SpringSource должно развеять последние сомнения в том, что Groovy и Grails созрели для использования в корпоративных приложениях.
Groovy может показаться немного экзотической технологией, однако важно помнить, что он полностью реализован на стандартном Java. Таким образом, как бы сильно работа с Grails ни отличалась от использования других инфраструктур, в результате вы все равно получите WAR-файл, удовлетворяющий спецификации Java EE.
В этой статье рассказывается о работе с некоторыми средствами для мониторинга и конфигурирования приложений, которые давно применяются в корпоративных системах. Вы узнаете об инструментировании вашего приложения Grails при помощи JMX, о конфигурировании объектов Spring в Grails, а также о первоначальной настройке log4j в Config.groovy и их последующем программном редактировании через JMX.
Инструментирование при помощи JMX
Технология JMX появилась в 2000 г.; она была описана в одном из наиболее ранних запросов JSR (JSR 3, если быть точным). В связи с тем, что Java набирала популярность в качестве языка для реализации серверных решений, возникла острая необходимость в средствах, позволяющих настраивать и конфигурировать выполняющееся приложение удаленным образом. В 2004 г. Sun инструментировала саму JVM при помощи JMX и включила в стандартную поставку JDK 1.5 такие вспомогательные средства как, например, JConsole.
JMX предоставляет единый согласованный интерфейс для мониторинга JVM, сервера приложений, а также ваших классов. Информация обо всех интересующих вас компонентах выводится на консоль управления при помощи специальных управляемых объектов (managed beans или сокращенно MBeans).
Замечание. Более подробная информация о JMX приведена в статье Теория и практика Java: инструментирование приложений при помощи JMX.
Объекты MBean выполняют примерно ту же функцию, что и всевозможные приборы, счетчики и переключатели в вашем автомобиле. Некоторые из них доступны только для чтения как, например спидометр, а значения других можно изменять (аналогично педали акселератора). Однако эта аналогия перестает работать, если принять во внимание, что объекты MBeans, как правило, управляются удаленным образом. Вы можете себе представить удаленное включение радио или сигнала поворота в своей машине?
Активизация локального агента JMX
Для того чтобы начать использовать JMX для мониторинга его необходимо активировать. В Java 5 это делается при помощи специальных параметров, передаваемых JVM (в Java 6 они передаются по умолчанию, однако вы все равно можете их установить чтобы переопределить стандартные значения). На жаргоне JMX передача этих параметров означает настройку JMX-агента. Параметры приведены в листинге 1.
Листинг 1. Параметры, передаваемые JVM для активизации мониторинга через JMX
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=localhost
|
В некоторых руководствах по JMX предлагается создавать глобальную переменную JAVA_OPTS для хранения всех флагов. Другие же авторы предпочитают передавать все параметры в командной строке: java -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=localhost someExampleClass.
В среде эксплуатации системы оба этих подхода работают, но ни один нельзя считать идеальным. Исходя из моего опыта, лучше всего значения флагов устанавливать в скрипте, запускающем сервер, поскольку надеяться на свою память и вводить их каждый раз по меньшей мере рискованно. При этом следует избегать использования глобальных переменных вроде CLASSPATH и JAVA_OPTS по двум причинам: во-первых, в этом случае потребуются дополнительные действия при клонировании серверов (гораздо легче просто скопировать стартовый скрипт), а во-вторых, всем Java-процессам, выполняющимся на этом компьютере, придется работать с одним набором конфигурационных параметров. Разумеется, можно подробно описать все детали конфигурирования, однако значительно проще устранить проблему, чем ее документировать.
Если вы работаете с операционными системами UNIX®, Linux® или Mac OS X, то стартовый скрипт Grails находится в файле JAVA_OPTS. Отредактируйте его, добавив строчки, показанные в листинге 2.
Листинг 2. Активизация мониторинга через JMX в скриптах запуска Grails в операционных системах UNIX, Linux и Mac OS X
#!/bin/sh
DIRNAME='dirname "$0"'
. "$DIRNAME/startGrails"
export JAVA_OPTS="-Dcom.sun.management.jmxremote"
export JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=localhost"
startGrails org.codehaus.groovy.grails.cli.GrailsScriptRunner "$@"
|
В Windows® скрипт для запуска Grails находится в файле $GRAILS_HOME/bin/grails.bat. Добавьте в него две строки, показанные в листинге 3, перед тем как запускать startGrails.bat.
Листинг 3. Активизация мониторинга через JMX в скрипте запуска Grails в Windows
set JAVA_OPTS=-Dcom.sun.management.jmxremote
set JAVA_OPTS=%JAVA_OPTS% -Djava.rmi.server.hostname=localhost
|
Обратите внимание, что в обоих скриптах переопределяется значение глобальной переменной JAVA_OPTS (если она существует). Это переопределение происходит только в рамках данного процесса и не влияет на глобальное значение переменной окружения. Это делается именно для того, чтобы случайно не испортить существующие настройки. Если ваши приложения зависят от существующих глобальных переменных, то не забудьте указать их в начале присвоения, аналогично тому, как это сделано в листингах 2 и 3.
Теперь Grails можно запустить, выполнив команду grails run-app. При этом в консоль не будет выведено никакой новой информации, однако сервер приложений теперь готов для мониторинга.
Для мониторинга JMX-агентов используются JMX-клиенты, которые могут представлять собой графические настольные приложения, такие как, например, JConsole (поставляется вместе с Java версии 5 и выше) или Web-приложения (поставляются вместе с большинством серверов, подобных Tomcat и JBoss). Более того, можно осуществлять программный мониторинг агентов, о чем будет рассказано ближе к концу статьи.
Далее откройте еще одно окно командного интерпретатора и выполните команду jconsole. Вы должны увидеть Grails в списке локальных агентов JMX, как показано на рисунке 1. Кликните мышью на Grails, а затем нажмите на кнопку Connect.
Рисунок 1. Список локальных агентов JMX в JConsole
Учтите, что по соображениям безопасности локальные JMX-агенты можно использовать в Windows только при работе с NTFS. Несмотря на то, что при использовании файловых систем FAT и FAT32 возможны проблемы, не волнуйтесь. В следующем разделе будет рассказано о конфигурировании агентов для удаленного доступа. Даже если агент и клиент физически выполняются на одном компьютере, это позволит обойти проблему, связанную с безопасностью.
После установки соединения вы должны увидеть сводную страницу, подобную показанной на рисунке 2.
Рисунок 2. Сводная страница в JConsole
Обратите внимание на закладки Memory, Threads, Classes и VM, которые позволяют в реальном времени наблюдать картину происходящего внутри JVM. Вам будет показано, хватает ли серверу физический памяти, число выполняющихся потоков и даже время, в течение которого был запущен сервер. Это само по себе интересно, однако еще больший интерес представляет закладка MBeans, на которой показаны данные о ваших классах.
Активизация удаленного агента JMX
Для того чтобы к агенту JMX можно было подключаться удаленным образом необходимо установить несколько дополнительных флагов при запуске JVM. Они нужны для открытия порта для управления агентом, а также задания настроек безопасности (или же ее отключения, как в данном примере).
Добавьте три строчки, показанные в листинге 4, в скрипт запуска Grails.
Листинг 4. Активизация удаленного мониторинга через JMX в скрипте запуска Grails
export JAVA_OPTS="-Dcom.sun.management.jmxremote"
export JAVA_OPTS=" $JAVA_OPTS -Djava.rmi.server.hostname=localhost"
export JAVA_OPTS=" $JAVA_OPTS -Dcom.sun.management.jmxremote.port=9004"
export JAVA_OPTS=" $JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
export JAVA_OPTS=" $JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
|
Перезапустите Grails, чтобы новые настройки вступили в силу. Также перезапустите JConsole, после чего перейдите на закладку Remote и подсоединитесь к localhost по порту 9004 (рисунок 3).
Рисунок 3. Подключение к удаленному агенту JMX в JConsole
Существует один простой способ проверки того, что мониторинг удаленной JVM осуществляется (даже если она физически выполняется на том же компьютере). Перейдите на закладку MBeans, раскройте дерево java.lang слева и выберите элемент Runtime. Затем дважды кликните на InputArguments в окне Attributes в правой части экрана. Вы должны увидеть все настройки для удаленного доступа к JMX, как показано на рисунке 4.
Рисунок 4. Параметры активизации удаленного агента JMX, переданные при запуске JVM
Не закрывая пока это окно, откройте новое соединение в меню Connection. Далее перейдите на закладку Remote и теперь оставьте в силе параметры по умолчанию localhost и порт 0). Затем раскройте элемент InputArguments, соответствующий объекту Runtime на закладке MBeans. Обратите внимание, что значения флагов для удаленного доступа к JMX не установлены (рисунок 5).
Рисунок 5. Мониторинг двух разных агентов JMX
Строчка "Monitoring Self" в заголовке последнего открытого окна говорит о том, что второй экземпляр JConsole осуществляет мониторинг себя самого.
Теперь, когда запущен JConsole, выполняющий мониторинг вашего приложения Grails, пришло время практических экспериментов, например изменения настроек журналирования. Однако перед этим необходимо познакомиться с последним недостающим элементом в этой JMX-головомке: сервером MBean.
Элемент Runtime в интерфейсе JConsole представляет собой объект MBean. Для того чтобы обеспечить доступ к объектам MBean со стороны клиентов JMX, их необходимо зарегистрировать в сервере MBean, выполняющемся внутри агента JMX. Иногда приходится слышать, что термины "агент JMX" и "сервер MBean" используются как синонимы, однако в реальности сервер MBean – это всего лишь один из многих компонентов, выполняющихся внутри агента JMX.
Для программной регистрации объекта MBean служит метод MBeanServer.registerMBean(). Однако в Grails для этого используется конфигурационный файл Spring.
Spring занимает центральное место в технологии Grails. Она представляет собой инфраструктуру, управляющую внедрением зависимостей (dependency injection), которая контролирует взаимодействие между классами. Более подробная информация о Spring приведена по ссылке в разделе Ресурсы.
С точки зрения JMX, этот процесс выглядит как регистрация объекта MBean в сервере MBean. Однако в терминах Spring это означает, что ссылка на объект MBean внедряется в сервер MBean. Несмотря на различия в терминологии, результат остается неизменным: объект MBean становится доступным для клиентов JMX.
Сначала создайте файл с именем resources.xml в каталоге grails-app/conf/spring (далее будет рассказано о связи между файлами resources.groovy и resources.xml). Поместите в него заготовку, приведенную в листинге 5.
Листинг 5. Конфигурирование инфраструктуры Spring/JMX в файле resources.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
<property name="beans">
<map>
</map>
</property>
</bean>
</beans>
|
На этом этапе можно перезапустить Grails чтобы убедиться, что базовая конфигурация корректна. Однако это только пол-дела: у нас уже есть сервер MBean, но нет объектов MBean. Объекты mbeanServer и exporter , описанные в конфигурации, являются частью инфраструктуры для регистрации объектов MBean. Объект mbeanServer хранит ссылку на существующий сервер MBean. В него также передается ссылка на объект exporter, через который клиенты JMX, такие как JConsole, смогут получать список зарегистрированных объектов MBean. Все, что осталось – это зарегистрировать нужные MBean, добавив их в ассоциативный массив внутри exporter. Этим мы займемся в следующем разделе.
Заглянув в файл grails-app/conf/Config.groovy, вы увидите настройки log4j, как показано в листинге 6.
Листинг 6. Настройки log4j в файле Config.groovy
log4j {
appender.stdout = "org.apache.log4j.ConsoleAppender"
appender.'stdout.layout'="org.apache.log4j.PatternLayout"
appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n'
// и так далее...
}
|
Большинство сообщений, выводимых в консоль при запуске приложения Grails, являются сообщениями log4j. Они выводятся классом org.apache.log4j.ConsoleAppender (за более подробной информацией о log4j обратитесь к разделу Ресурсы).
Регистрация объекта MBean для работы с log4j
Если вам требуется изменить настройки журналирования в приложении Grails без JMX, то проще всего отредактировать конфигурационный файл и перезапустить программу. Однако что делать, если настройки желательно скорректировать без перезапуска сервера либо удаленным образом? Именно для таких задач и предназначен JMX, тем более что в состав log4j входит соответствующий объект MBean. Все, что от вас требуется – это зарегистрировать его.
Добавьте XML-элемент entry, показанный в листинге 7, в resources.xml. Таким образом серверу MBean будет передана ссылка на объект MBean, управляющий настройками log4j.
Листинг 7. Внедрение ссылки на объект MBean в сервер MBean
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
<property name="beans">
<map>
<entry key="log4j:hierarchy=default">
<bean class="org.apache.log4j.jmx.HierarchyDynamicMBean"/>
</entry>
</map>
</property>
</bean>
|
Перезапустите Grails а затем JConsole. Подключившись к localhost через порт 9004, вы должны увидеть новый MBean log4j на закладке MBeans. Раскройте элемент log4j в дереве, выберите элемент default, а затем перейдите на закладку Info. На ней вы должны увидеть знакомые настройки log4j, которые вы ранее добавили в resources.xml (рисунок 6).
Рисунок 6. Параметры по умолчанию для объекта MBean
Теперь, после того как log4j стал доступны через JMX, можно попробовать изменить настройки журналирования.
Изменение настроек log4j в процессе работы приложения
Представьте на минуту, что в поведении вашего приложения Grails появились некоторые странности, и требуется получить лучшее представление о том, что происходит внутри. Заглянув в файл grails-app/conf/Config.groovy, вы увидите, что корневой логгер должен выводить информацию в консоль, однако фильтр настроен таким образом (rootLogger="error,stdout"), что блокирует все сообщения с уровнем ниже error. Ваша задача заключается в том, чтобы понизить порог уровня сообщений до trace, чтобы увеличить объем выводимой информации.
Теперь вернемся к JConsole. Внутри элемента log4j должен находиться корневой объект MBean, причем значением его атрибута priority является ERROR, как и в файле Config.groovy. Дважды щелкните на этом значении и измените его на TRACE, как показано на рисунке 7.
Рисунок 7. Изменение приоритета сообщений корневого логгера с
ERROR на TRACE
Для того чтобы убедиться, что объем выводимой информации действительно увеличился, нажмите на ссылку AirportMappingController на домашней странице вашего приложения Grails в браузере. Среди большого числа новых журнальных сообщений вы должны увидеть подробности того, что именно делает Grails для вывода данного списка. Пример приведен в листинге 8.
Листинг 8. Более подробный вывод сообщений log4j
[11277653] metaclass.RedirectDynamicMethod
Dynamic method [redirect] looking up URL mapping for
controller [airportMapping] and action [list] and
params [["action":"index", "controller":"airportMapping"]]
with [URL Mappings
------------
org.codehaus.groovy.grails.web.mapping.ResponseCodeUrlMapping@1bab0b
/rest/airport/(*)?
/(*)/(*)?/(*)?
]
[11277653] metaclass.RedirectDynamicMethod Dynamic method
[redirect] mapped to URL [/trip/airportMapping/list]
[11277653] metaclass.RedirectDynamicMethod Dynamic method
[redirect] forwarding request to [/trip/airportMapping/list]
[11277653] metaclass.RedirectDynamicMethod Executing redirect
with response
[com.opensymphony.module.sitemesh.filter.PageResponseWrapper@19243f]
|
Изменение настроек ConversionPattern в log4j
Теперь предположим, что требуется изменить шаблон вывода журнальных сообщений. В файле Config.groovy за это отвечает строка appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n'. Ознакомившись с документацией по log4j, вы решили сделать его более информативным.
Кликните мышью на MBean stdout в JConsole и измените значение атрибута conversionPattern на [%5p] %d{hh:mm:ss} (%F:%M:%L)%n%m%n%n (рисунок 8). После того как приложение сгенерирует новые журнальные сообщения будет кратко рассказано о том, что означает эта загадочная надпись (более подробную информацию о conversionPattern в log4j можно найти по ссылкам в разделе Ресурсы).
Рисунок 8. Изменение значения атрибута
conversionPattern у объекта PatternLayout
Теперь нажмите на ссылку home, а затем вновь на AirportMappingController на домашней странице. Как видите, формат выводимых сообщений изменился кардинальным образом (листинг 9).
Листинг 9. Вывод журнальных сообщений в консоль в новом формате
[DEBUG] 09:04:47 (RedirectDynamicMethod.java:invoke:127)
Dynamic method [redirect] looking up URL mapping for controller
[airportMapping] and action [list] and params
[["action":"index", "controller":"airportMapping"]] with [URL Mappings
------------
org.codehaus.groovy.grails.web.mapping.ResponseCodeUrlMapping@e73cb7
/rest/airport/(*)?
/(*)/(*)?/(*)?
]
[DEBUG] 09:04:47 (RedirectDynamicMethod.java:invoke:144)
Dynamic method [redirect] mapped to URL [/trip/airportMapping/list]
[DEBUG] 09:04:47 (RedirectDynamicMethod.java:redirectResponse:162)
Dynamic method [redirect] forwarding request to [/trip/airportMapping/list]
[DEBUG] 09:04:47 (RedirectDynamicMethod.java:redirectResponse:168)
Executing redirect with response
[com.opensymphony.module.sitemesh.filter.PageResponseWrapper@47b2e7]
|
Теперь, когда вы видите результат, пришло время объяснить, как он достигается. %p выводит приоритет сообщений. Сообщения в листинге 9 имеют уровень приоритета DEBUG. %d{hh:mm:ss} показывает точное время сообщения в формате часы:минуты:секунды. (%F:%M:%L) выводит имя файла, метода и номер строки в скобках. Наконец, %n%m%n%n означает перевод строки, затем вывод самого сообщения, а далее еще двух новых строк.
Ни одно из изменений в настройках log4j, сделанное через JMX, не является постоянным. При перезапуске Grails все настройки вернутся к заданным в файле Config.groovy. Таким образом, вы можете экспериментировать с JMX как вам вздумается, не беспокоясь о возможности что-нибудь испортить. Особенно удобно экспериментировать с ConversionPattern через JMX – вы можете делать это до тех пор, пока не будет найден идеальный формат вывода сообщений. Главное – не забудьте скопировать найденный шаблон в Config.groovy, чтобы далее он применялся постоянно.
Вернемся к гипотетической ситуации с отладкой приложения Grails в реальном времени. Предположим, что вы так и нашли корень проблемы. Измените приоритет сообщений в корневом объекте MBean на ERROR, чтобы не замусоривать вывод.
Возможно, проблема скрывается в Hibernate. Заглянув снова в файл Config.groovy, вы обнаружите, что журнальный вывод отключен для классов из пакета org.hibernate. Не исключено, что полезнее будет сосредоточиться на информации, специфичной для конкретных классов, чем понижать порог приоритета для журнальных сообщений в рамках всего приложения.
Кликните мышью на MBean default в JConsole. Существует возможность не только изменять значения атрибутов, но и вызывать методы объектов MBean. Перейдите на закладку Operations, введите org.hibernate в качестве параметра name и нажмите на кнопку addLoggerMBean. В дереве в левой части экрана должен появиться новый объект MBean.
Далее нажмите на новый MBean с именем org.hibernate и измените значение его атрибута priority на DEBUG, как показано на рисунке 9.
Рисунок 9. Изменение приоритета сообщений у объекта MBean
org.hibernate
Теперь вернитесь к Web-браузеру, перейдите на домашнюю страницу и вновь нажмите на ссылку AirportMappingController. Вы должны увидеть длинный ряд отладочных сообщений, подобно приведенным в листинге 10.
Листинг 10. Вывод log4j, относящийся к классам Hibernate
[DEBUG] 10:05:52 (AbstractBatcher.java:logOpenPreparedStatement:366)
about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[DEBUG] 10:05:52 (ConnectionManager.java:openConnection:421)
opening JDBC connection
[DEBUG] 10:05:52 (AbstractBatcher.java:log:401)
select this_.airport_id as airport1_0_0_, this_.locid as locid0_0_,
this_.latitude as latitude0_0_, this_.longitude as longitude0_0_,
this_.airport_name as airport5_0_0_, this_.state as state0_0_
from usgs_airports this_ limit ?
[DEBUG] 10:05:52 (AbstractBatcher.java:logOpenResults:382)
about to open ResultSet (open ResultSets: 0, globally: 0)
[DEBUG] 10:05:52 (Loader.java:getRow:1173)
result row: EntityKey[AirportMapping#1]
[DEBUG] 10:05:52 (Loader.java:getRow:1173)
result row: EntityKey[AirportMapping#2]
|
Уделите некоторое время отладочным сообщениям Hibernate. Из них вы можете получить подробную информацию о том, что именно происходит в процессе выборки информации из базы данных и ее преобразования в список (ArrayList) объектов.
Использование компонента Bean Builder в Spring
Теперь, когда вы уже знаете, как конфигурировать JMX в файле resources.xml, пора сделать следующий шаг. В Grails конфигурирование объектов через Spring можно также описывать в файле resources.groovy. Переименуйте файл grails-app/conf/spring/resources.xml в resources.xml.old. После этого добавьте фрагмент кода из листинга 11 в resources.groovy.
Листинг 11. Конфигурирование объектов Spring при помощи Bean Builder
import org.springframework.jmx.support.MBeanServerFactoryBean
import org.springframework.jmx.export.MBeanExporter
import org.apache.log4j.jmx.HierarchyDynamicMBean
beans = {
log4jBean(HierarchyDynamicMBean)
mbeanServer(MBeanServerFactoryBean) {
locateExistingServerIfPossible=true
}
exporter(MBeanExporter) {
server = mbeanServer
beans = ["log4j:hierarchy=default":log4jBean]
}
}
|
Как видите, объекты Spring можно конфигурировать при помощи Groovy вместо XML. Ранее использование класса MarkupBuilder в Groovy демонстрировалось в статьях Grails и устаревшие базы данных и Grails и REST. Он представляет собой разновидность того же подхода, что и Bean Builder, за тем исключением, что последний используется только для описания объектов Spring.
Перезапустите Grails, JConsole и убедитесь, что ничего не изменилось по сравнению с вариантом приложения, в котором использовалась конфигурация в XML.
Описание объектов Spring в XML обладает тем преимуществом, что вы можете копировать фрагменты конфигураций из множества различных источников в Web. Однако использование Bean Builder лучше сочетается с конфигурированием остальных компонентов приложения Grails. К этому моменту вы уже видели такие скрипты конфигурирования, как DataSource.groovy, Config.groovy, BootStrap.groovy и Events.groovy. Конфигурирование в коде позволяет регистрировать объекты MBean в зависимости от характеристик среды, в которой выполняется приложение.
В листинге 12 приведен пример того, как объект log4jBean может регистрироваться в среде эксплуатации и скрываться в среде разработки приложения.
Листинг 12. Регистрация объекта JMX в зависимости от результата проверки условия
import org.springframework.jmx.support.MBeanServerFactoryBean
import org.springframework.jmx.export.MBeanExporter
import org.apache.log4j.jmx.HierarchyDynamicMBean
import grails.util.GrailsUtil
beans = {
log4jBean(HierarchyDynamicMBean)
mbeanServer(MBeanServerFactoryBean) {
locateExistingServerIfPossible=true
}
switch(GrailsUtil.environment){
case "development":
break
case "production":
exporter(MBeanExporter) {
server = mbeanServer
beans = ["log4j:hierarchy=default":log4jBean]
}
break
}
}
|
Выполните команду grails run-app и убедитесь, что в среде разработки MBean log4j не показывается в JConsole. Теперь запустите Grails в среде эксплуатации, выполнив команду grails prod run-app (или grails war) и разверните WAR-файл в своем сервере приложений. Перезапустив JConsole, вы вновь должны увидеть данный объект MBean.
Последней темой, которая будет затронута в этой статье, является обращение к JMX-объектам MBean программным образом. При всех достоинствах графического интерфейса JConsole, программное изменение объектов MBean из скриптов Groovy обладает еще более широкими возможностями.
Для начала создайте файл с именем testJmx.groovy и поместите в него код из листинга 13.
Листинг 13. Вызов удаленного агента JMX в Groovy
import javax.management.MBeanServerConnection
import javax.management.remote.JMXConnectorFactory
import javax.management.remote.JMXServiceURL
def agentUrl = "service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi"
def connector = JMXConnectorFactory.connect(new JMXServiceURL(agentUrl))
def server = connector.mBeanServerConnection
println "Number of registered MBeans: ${server.mBeanCount}"
println "\nRegistered Domains:"
server.domains.each{println it}
println "\nRegistered MBeans:"
server.queryNames(null, null).each{println it}
|
Если Grails запущен, то вы должны увидеть вывод, подобный показанному в листинге 14.
Листинг 14. Вывод скрипта testJmx.groovy
$ groovy testJmx.groovy
Number of registered MBeans: 20
Registered Domains:
java.util.logging
JMImplementation
java.lang
log4j
Registered MBeans:
java.lang:type=MemoryManager,name=CodeCacheManager
java.lang:type=Compilation
java.lang:type=GarbageCollector,name=Copy
java.lang:type=MemoryPool,name=Eden Space
log4j:appender=stdout
java.lang:type=Runtime
log4j:hierarchy=default
log4j:logger=root
log4j:appender=stdout,layout=org.apache.log4j.PatternLayout
java.lang:type=ClassLoading
java.lang:type=MemoryPool,name=Survivor Space
java.lang:type=Threading
java.lang:type=GarbageCollector,name=MarkSweepCompact
java.util.logging:type=Logging
java.lang:type=Memory
java.lang:type=OperatingSystem
java.lang:type=MemoryPool,name=Code Cache
java.lang:type=MemoryPool,name=Tenured Gen
java.lang:type=MemoryPool,name=Perm Gen
JMImplementation:type=MBeanServerDelegate
|
Замечание. Учтите, что скрипт testJmx.groovy может сгенерировать исключение groovy.lang.MissingMethodException, подобное приведенному в листинге 15.
Листинг 15. Возможное исключение JMX
Caught: groovy.lang.MissingMethodException: No signature of method:
javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.queryNames()
is applicable for argument types: (java.lang.String, null)
|
В этом случае удалите файл mx4j-3.0.2.jar из каталога $GROOVY_HOME/lib. Он был включен в дистрибутив Groovy с целью поддержки JMX в JDK 1.4, однако конфликтует с более поздними версиями платформы Java.
Самый интересный момент в этом скрипте – это возвращение объекта типа javax.management.MBeanServer методом connector.mBeanServerConnection (как вы помните, вызов метода с именем getFoo() в Java может быть сокращен до foo в Groovy). Вызов server.mBeanCount возвращает общее число зарегистрированных объектов MBean. Метод server.domains возвращает строковый массив имен доменов, которые представляют собой первую часть идентификаторов MBean. Полностью квалифицированное имя MBean также включает список пар типа "ключ/значение", разделенный запятыми. Метод server.queryNames(null, null) возвращает множество всех зарегистрированных объектов MBean. За более подробной информацией о методах класса MBeanServer обратитесь по ссылкам в разделе Ресурсы.
Для того чтобы получить ссылку на конкретный объект MBean, добавьте содержимое листинга 16 в конец скрипта.
Листинг 16. Доступ к объекту MBean
println "\nHere is the Runtime MBean:"
def mbean = new GroovyMBean(server, "java.lang:type=Runtime")
println mbean
|
Если вы знаете имя нужного объекта MBean и подключились к серверу MBean, то для получения ссылки на нужный экземпляр GroovyMBean достаточно одной строчки кода. Вывод скрипта показан в листинге 17.
Листинг 17. Сообщения, выводимые экземпляром
GroovyMBean
Here is the Runtime MBean:
MBean Name:
java.lang:type=Runtime
Attributes:
(r) javax.management.openmbean.TabularData SystemProperties
(r) java.lang.String VmVersion
(r) java.lang.String VmName
(r) java.lang.String SpecName
(r) [Ljava.lang.String; InputArguments
(r) java.lang.String ManagementSpecVersion
(r) java.lang.String SpecVendor
(r) long Uptime
(r) long StartTime
(r) java.lang.String LibraryPath
(r) java.lang.String BootClassPath
(r) java.lang.String VmVendor
(r) java.lang.String ClassPath
(r) java.lang.String SpecVersion
(r) java.lang.String Name
(r) boolean BootClassPathSupported
|
Помните набор параметров InputArguments, о которых упоминалось в начале статьи? Это те самые параметры с префиксом -D, которые передавались JVM при запуске. С их помощью вы могли удостовериться, что действительно установлено соединение с удаленным агентом JMX. Добавьте две строки кода из листинга 18, чтобы вывести их значения.
Листинг 18. Доступ к значениям
InputArguments объекта Runtime
println "\nHere are the InputArguments:"
mbean.InputArguments.each{println it}
|
Вы должны увидеть результат как в листинге 19, который означает что вы вернулись к тому, с чего начинали.
Листинг 19. Значения параметров запуска JVM (
InputArguments)
Here are the InputArguments:
-Xserver
-Xmx512M
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.port=9004
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dprogram.name=grails
-Dgroovy.starter.conf=/opt/grails/conf/groovy-starter.conf
-Dgrails.home=/opt/grails
-Dbase.dir=.
-Dtools.jar=/Library/Java/Home/lib/tools.jar
|
Более подробную информацию о GroovyMBean можно получить по ссылкам в разделе Ресурсы.
Grails готов для использования в корпоративных приложениях. Популярные библиотеки, используемые в таких системах, в частности JMX, Spring и log4j, доступны в Grails, поскольку, несмотря на все внешние различия, разработка все равно производится в рамках платформы Java EE.
Этой статьей завершается годовая серия колонок, посвященных приложению для планирования путешествий. Я намеренно использовал одно и то же приложение во всех статьях, чтобы можно было сосредоточиться на функциональности Grails. Я буду придерживаться того же принципа и в следующем году, однако постараюсь расширить круг приложений Grails.
Например, в следующем месяце мы поговорим о новой системе для ведения блогов. Вы вспомните о том, как начинать разработку новых приложений Grails, однако в этом материале не будет ничего нового. Далее мы обратимся к принципам REST в Grails, в соответствии с которыми будет организована полнофункциональная инфраструктура Atom. Для создания календарей и облаков тегов будут вновь использоваться знакомые технологии JSON и Ajax. А еще через пару месяцев мы займемся чем-нибудь еще.
Grails продолжает набирать популярность с каждым новым Web-сайтом. Отличительным признаком зрелости инфраструктуры для создания Web-приложений является ее использование множеством различных способов. В следующем году в статьях серии "Изучение Grails" будет рассказано о разнообразии Web-сайтов, которые можно создать при помощи Grails. Пока же – получайте удовольствие от изучения Grails.
Научиться
- Оригинал статьи: Mastering Grails: Grails in the enterprise (Скотт Дэвис, developerWorks, декабрь 2008 г.). (EN)
- Прочитайте другие статьи серии Изучение Grails, которые помогут вам глубже понять возможности Grails и варианты ее применения. (EN)
- Посетите Web-сайт Grails. (EN)
- Прочитайте последнюю книгу Скотта Дэвиса Groovy Recipes: Greasing the Wheels of Java и узнайте больше о Groovy и Grails. (EN)
- Ознакомьтесь с документацией по инфраструктуре Grails – своего рода "библией" данной технологии. (EN)
- Обратите внимание путеводитель по JMX от Sun под названием Мониторинг и управление при помощи JMX. (EN)
- Прочитайте документацию Javadoc по классу
PatternLayout. (EN) - Узнайте больше о методах класса
MBeanServer. (EN) - Ознакомьтесь со статьей Groovy и JMX, в которой приводится более подробная информация о классах
GroovyMBean. (EN) - Прочитайте о компоненте Bean Builder в Grails, который позволяет описывать объекты Spring программным образом. (EN)
- В статьях серии developerWorks Groovy на практике описываются реальные варианты использования Groovy, которые помогут вам понять, как и когда стоит применять данный язык. (EN)
- Узнайте больше о Groovy, посетив официальный сайт проекта. (EN)
- На сайте AboutGroovy.com вы найдете последние новости из мира Groovy и ссылки на статьи. (EN)
- Обратитесь к магазину технической литературы, в котором представлены книги на данную и другие темы. (EN)
- Сотни статей по всем аспектам программирования на Java можно найти на сайте developerWorks, в разделе Технология Java.
Получить продукты и технологии
-
Grails: загрузите последнюю версию Grails. (EN)
Обсудить
- Читайте блоги developerWorks и присоединяйтесь к нашему сообществу. (EN)