Изучение Grails: Использование Grails в корпоративных приложениях

Применение Grails вместе с JMX, Spring и log4j

В этой статье серии Изучение Grails Скотт Дэвис развеет все сомнения насчет готовности Grails к использованию в корпоративных приложениях. Вы узнаете как применять Grails в сочетании с такими признанными библиотеками калибра корпоративных систем, как JMX (инфраструктура для управления расширениями Java™), Spring и log4j.

Скотт Дэвис, главный редактор, AboutGroovy.com

Скотт Дэвис (Scott Davis) является международно признанным автором, лектором и разработчиком программного обеспечения. Среди его книг: Groovy Recipes: Greasing the Wheels of Java, GIS for Web Developers: Adding Where to Your Application, The Google Maps API и JBoss At Work.



10.06.2011

Меня часто спрашивают, готов ли 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.

Об этой серии

Grails – это современная инфраструктура для разработки Web-приложений, сочетающая использование знакомых Java-технологий, например, Spring и Hibernate, с такими популярными в настоящее время принципами, как соглашения по конфигурированию (convention over configuration). Будучи написанной на языке Groovy, Grails позволяет легко интегрировать старый Java-код в новые приложения, предоставляя гибкие возможности динамического скриптового языка. Изучение Grails навсегда изменит ваш взгляд на Web-разработку.

Инструментирование при помощи 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

На этапах разработки и тестирования приложения легче всего запускать агента и клиента JMX локально. Однако в среде эксплуатации системы преимущества JMX проявляются в полной мере лишь при удаленном мониторинге агентов. JConsole потребляет те же ресурсы (память, процессорное время), что и любой другой Java-процесс. Это может представлять собой проблему, поскольку рабочий сервер, подвергаемый мониторингу, и так находится под нагрузкой. Еще более важным преимуществом удаленного мониторинга является то, что вы можете наблюдать за множеством серверов с одного рабочего места, обладая, таким образом, полным контролем над вычислительными ресурсами.

Разумеется, мониторинг рабочих серверов должен сочетаться с их адекватной защитой от несанкционированного доступа. Для этого можно установить пароль на доступ, а в идеале – аутентификакцию на основе публичных и секретных ключей (см. раздел Ресурсы).

Для того чтобы начать использовать 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 в JConsole

Учтите, что по соображениям безопасности локальные JMX-агенты можно использовать в Windows только при работе с NTFS. Несмотря на то, что при использовании файловых систем FAT и FAT32 возможны проблемы, не волнуйтесь. В следующем разделе будет рассказано о конфигурировании агентов для удаленного доступа. Даже если агент и клиент физически выполняются на одном компьютере, это позволит обойти проблему, связанную с безопасностью.

После установки соединения вы должны увидеть сводную страницу, подобную показанной на рисунке 2.

Рисунок 2. Сводная страница в JConsole
Сводная страница в JConsole

Обратите внимание на закладки Memory, Threads, Classes и VM, которые позволяют в реальном времени наблюдать картину происходящего внутри JVM. Вам будет показано, хватает ли серверу физический памяти, число выполняющихся потоков и даже время, в течение которого был запущен сервер. Это само по себе интересно, однако еще больший интерес представляет закладка MBeans, на которой показаны данные о ваших классах.

Активизация удаленного агента JMX

Не делайте так на практике

Эта конфигурация никогда не должна использоваться в реальной системе. Для удобства демонстрации в данном примере полностью отключены механизмы аутентификации и шифрования. Обратитесь к разделу Ресурсы за подробными инструкциями по обеспечению безопасности при удаленном управлении агентами 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
Подключение к удаленному агенту JMX в JConsole

Существует один простой способ проверки того, что мониторинг удаленной JVM осуществляется (даже если она физически выполняется на том же компьютере). Перейдите на закладку MBeans, раскройте дерево java.lang слева и выберите элемент Runtime. Затем дважды кликните на InputArguments в окне Attributes в правой части экрана. Вы должны увидеть все настройки для удаленного доступа к JMX, как показано на рисунке 4.

Рисунок 4. Параметры активизации удаленного агента JMX, переданные при запуске JVM
Параметры активизации удаленного агента JMX, переданные при запуске JVM

Не закрывая пока это окно, откройте новое соединение в меню Connection. Далее перейдите на закладку Remote и теперь оставьте в силе параметры по умолчанию localhost и порт 0). Затем раскройте элемент InputArguments, соответствующий объекту Runtime на закладке MBeans. Обратите внимание, что значения флагов для удаленного доступа к JMX не установлены (рисунок 5).

Рисунок 5. Мониторинг двух разных агентов JMX
Мониторинг двух разных агентов JMX

Строчка "Monitoring Self" в заголовке последнего открытого окна говорит о том, что второй экземпляр JConsole осуществляет мониторинг себя самого.

Теперь, когда запущен JConsole, выполняющий мониторинг вашего приложения Grails, пришло время практических экспериментов, например изменения настроек журналирования. Однако перед этим необходимо познакомиться с последним недостающим элементом в этой JMX-головомке: сервером MBean.


Сервер MBean, Grails и Spring

Элемент 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. Этим мы займемся в следующем разделе.


Использование log4j с Grails

Заглянув в файл 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
Параметры по умолчанию для объекта 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
Изменение приоритета сообщений корневого логгера с 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]

В каких случаях можно спокойно игнорировать фатальную ошибку (Fatal Error)?

Если у вас есть опыт работы с Grails 1.0.3, то, возможно, вы замечали загадочную ошибку, которая часто появлялась в консольном выводе: [Fatal Error] :-1:-1: Premature end of file. Большинство разработчиков ее игнорировали, поскольку на практике она не приводила к сбоям, в том числе фатальным.

Если задать уровень сообщений trace, то можно увидеть некоторые подробности этой, в теории фатальной, ошибки: converters.XMLParsingParameterCreationListener Error parsing incoming XML request: Error parsing XML.

Этот более подробный вывод означает, что Grails пытается анализировать каждый запрос так, как если бы он был представлен в виде XML. Большинство запросов не представлены в XML, поэтому обработчик сигнализирует об этой ошибке, но затем корректно продолжает свою работу.

Эта безобидная, но назойливая ошибка была исправлена в версии 1.0.4.

Изменение настроек 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
Изменение значения атрибута 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, чтобы далее он применялся постоянно.


Отладочный вывод Hibernate

Вернемся к гипотетической ситуации с отладкой приложения 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
Изменение приоритета сообщений у объекта 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 в Groovy

Последней темой, которая будет затронута в этой статье, является обращение к 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.

Ресурсы

Научиться

Получить продукты и технологии

  • Grails: загрузите последнюю версию Grails. (EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=679256
ArticleTitle=Изучение Grails: Использование Grails в корпоративных приложениях
publish-date=06102011