Статьи

Взгляд в микроконтейнер JBoss, часть I — Компонентные модели

Глядя на текущее состояние Java, мы видим, что POJO (простые старые объекты Java) снова правят землей. Их доминирование простирается от корпоративных приложений до сервисов промежуточного программного обеспечения. В JBoss мы были известны нашим модульным ядром на основе JMX . Сервер приложений был не более чем набором гибких MBean- компонентов и мощным микроядром в середине. Но, как вы могли почувствовать, грядут перемены, мы все же хотели быть впереди всех. Мы могли видеть различные модели компонентов на основе POJO, появляющиеся повсюду (EJB3, JPA, Spring, Guice,… и многие другие), но не было ничего, что могло бы связать их всех, сгладить различия в модели с одним компонентом , Отсюда и появился проект «Микроконтейнер».

Проект JBoss Microcontainer о многом. Возможности Микроконтейнера варьируются от абстракции отражения, виртуальной файловой системы, простого конечного автомата до прозрачной интеграции AOP, нового уровня загрузки классов, инфраструктуры развертывания и реализации платформы OSGi. Я постараюсь обратиться к ним по всей короткой серии статей, которые будут опубликованы здесь, на DZone. В этой статье будут рассмотрены модели компонентов микроконтейнера.

Прочитайте другие части эксклюзивной серии микроконтейнеров JBoss от DZone :

 

 

Что такое компонентная модель?

Что мы считаем компонентной моделью? Прежде всего, что мы считаем компонентом? Одним из абстрактных способов выразить это было бы то, что «компоненты — это многократно используемые программы, которые вы можете легко разрабатывать и собирать для создания сложных приложений». Чтобы рассматривать кучу компонентов в качестве реальной модели, нам также необходимо объявить, какие виды взаимодействия мы разрешаем.

JMX MBeans — один из примеров компонентной модели. Их взаимодействие включает выполнение операций MBean, обращение к атрибутам, установку атрибутов и объявление явных зависимостей между именованными MBean.

Как уже упоминалось, мы уже продвинули обработку JMX с помощью MicroKernel . И, как и ожидалось, микроконтейнер принес широкую поддержку POJO. Поведение по умолчанию и взаимодействия в микроконтейнере — это то, что вы обычно получаете из любого другого контейнера IoC, и они аналогичны функциональности, предоставляемой MBeans: простые вызовы методов для операций, установщики / получатели для атрибутов и явные зависимости.

Однако наличие только этой функциональности означало бы, что мы не добились намного большего, чем просто сняли боль с объявления MBeans, поэтому для нас было логичным сделать что-то большее. Я оставлю обсуждение этих новых функций IoC для следующей статьи в серии.

Существует множество существующих моделей компонентов POJO , среди которых наиболее популярны Guice и Spring . Эффективная интеграция с этими структурами была для нас важной целью.

Настройка демо-среды

Прежде чем мы начнем, я хотел бы сначала описать различные части, которые составляют демо. Весь исходный код можно найти по этому адресу нашего хранилища Subversion:

http://anonsvn.jboss.org/repos/jbossas/projects/demos/microcontainer/branches/DZone_1_0/

 

Проект полностью подготовлен, поэтому его легко настроить в соответствии со своей IDE.

Сначала я перейду к подпроектам в демоверсии и опишу их использование. В конце серии статей я более подробно расскажу о том, что делают некоторые подпроекты.

Ниже приведены демонстрационные материалы и подпроекты JBoss Microcontainer, относящиеся к этой статье:

• bootstrap (как следует из названия, он загружает микроконтейнер с демонстрационным кодом)
• jmx (добавляет понятие JMX к начальной загрузке демо)
• модели (исходный код наших компонентов / сервисов)

В демоверсии есть только одна переменная, которую вам нужно установить — demos home — но даже эта может быть необязательной, если вы вынули свой проект в каталог \ projects \ demos. В противном случае вам нужно установить системное свойство demos.home (например, -Ddemos.home = <мой домашний каталог демонстраций>). Теперь вы сможете запускать JMXMain в качестве основного класса. Убедитесь, что вы включили подпроект моделей в classpath, поскольку некоторые службы требуют дополнительных классов в classpath, что несколько больше, чем ожидает подпроект jmx. После загрузки микроконтейнера он начинает сканировать каталог $ {demos.home} / sandbox на наличие изменений. Теперь все, что нам нужно сделать, это предоставить развертываемый модуль и поместить его туда.

модели

Давайте теперь обратим наше внимание на подпроект проекта. Вот откуда должен был появиться ранее упомянутый развертываемый блок. Вы можете увидеть, все ли на месте, создав подпроект модели (пакет mvn) и поместив его в песочницу. Вы должны получить кучу отладочных и информационных сообщений в журнале консоли, показывающих, как загружался микроконтейнер. Любое сообщение об ошибке указывает на некоторые проблемы.
Давайте подробно рассмотрим, что делает подпроект модели, его интеграционный код и попробуем повторно развернуть его. Если мы посмотрим на каталог моделей src / main / resources / META-INF, то увидим множество файлов ресурсов -beans.xml и один файл -service.xml. Вы заметите, что у каждого есть осмысленное имя, которое соответствует пакету исходного кода из каталога моделей src / main / java / org / jboss / demos / models. Давайте рассмотрим их один за другим, начиная с тех, которые не имеют зависимостей.

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="PlainPojo" class="org.jboss.demos.models.plain.Pojo"/>

<beanfactory name="PojoFactory" class="org.jboss.demos.models.plain.Pojo">
<property name="factoryClass">org.jboss.demos.models.plain.PojoFactory</property>
</beanfactory>

</deployment>

Это простой файл дескриптора бобов Micrcocontainer. Любой, кто пересек пути с каким-либо другим файлом конфигурации IoC, должен быть знаком с ним. И, как я уже упоминал, я расскажу о более продвинутом использовании в следующей статье.

Следующий файл показывает, что мы сделали для поддержки интеграции с Spring:

<beans xmlns="urn:jboss:spring-beans:2.0">

<!-- Adding @Spring annotation handler -->
<bean id="SpringAnnotationPlugin" class="org.jboss.spring.annotations.SpringBeanAnnotationPlugin" />

<bean id="SpringPojo" class="org.jboss.demos.models.spring.Pojo"/>

</beans>

 

Обратите внимание, что пространство имен этого файла отличается от файла plain-beans.xml предыдущего bean-компонента Microcontainer. Пространство имен urn: jboss: spring-beans: 2.0 указывает на нашу версию порта схемы Spring, то есть вы можете описать свой стиль Spring bean-компонентов, но тогда будет развернут микроконтейнер, а не понятие фабрики бинов Spring.

public class Pojo extends AbstractPojo implements BeanNameAware
{
private String beanName;

public void setBeanName(String name)
{
beanName = name;
}

public String getBeanName()
{
return beanName;
}

public void start()
{
if ("SpringPojo".equals(getBeanName()) == false)
throw new IllegalArgumentException("Name doesn't match: " + getBeanName());
}
}

 

Хотя бин SpringPojo имеет зависимость от Spring lib посредством реализации интерфейса BeanNameAware, эта зависимость существует только для того, чтобы раскрыть и смоделировать некоторые из функций обратного вызова Spring (подробнее см. SpringBeanAnnotationPlugin).

Поскольку мы представили интеграцию Spring, давайте посмотрим на интеграцию Guice. Как знают пользователи Guice, Guice — все о сопоставлении типов. Конфигурация bean-компонентов Guice выполняется через модули, что означает, что для генерации bean-компонентов необходимо реализовать модуль.

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="GuicePlugin" class="org.jboss.guice.spi.GuiceKernelRegistryEntryPlugin">
<constructor>
<parameter>
<array elementClass="com.google.inject.Module">
<bean class="org.jboss.demos.models.guice.PojoModule"/>
</array>
</parameter>
</constructor>
</bean>

</deployment>

 

Из этого файла можно просмотреть две важные части: PojoModule и GuiceKernelRegistryEntryPlugin. Первый, где мы настраиваем наши bean-компоненты:

public class PojoModule extends AbstractModule
{
private Controller controller;

@Constructor
public PojoModule(@Inject(bean = KernelConstants.KERNEL_CONTROLLER_NAME) Controller controller)
{
this.controller = controller;
}

protected void configure()
{
bind(Controller.class).toInstance(controller);
bind(IPojo.class).to(Pojo.class).in(Scopes.SINGLETON);
bind(IPojo.class).annotatedWith(FromMC.class).toProvider(GuiceIntegration.fromMicrocontainer(IPojo.class, "PlainPojo"));
}
}

 

Второй класс обеспечивает интеграцию с микроконтейнером:

public class GuiceKernelRegistryEntryPlugin implements KernelRegistryPlugin
{
private Injector injector;

public GuiceKernelRegistryEntryPlugin(Module... modules)
{
injector = Guice.createInjector(modules);
}

public void destroy()
{
injector = null;
}

public KernelRegistryEntry getEntry(Object name)
{
KernelRegistryEntry entry = null;
try
{
if (name instanceof Class<?>)
{
Class<?> clazz = (Class<?>)name;
entry = new AbstractKernelRegistryEntry(name, injector.getInstance(clazz));
}
else if (name instanceof Key)
{
Key<?> key = (Key<?>)name;
entry = new AbstractKernelRegistryEntry(name, injector.getInstance(key));
}
}
catch (Exception ignored)
{
}
return entry;
}
}

 

Обратите внимание на то, как мы создали Injector из модулей, а затем выполнили поиск на предмет соответствия bean-компонентам.
В mbeans-service.xml мы заявляем о нашем традиционном использовании MBeans:

<server>

<mbean code="org.jboss.demos.models.mbeans.Pojo" name="jboss.demos:service=pojo">
<attribute name="OtherPojo"><inject bean="PlainPojo"/></attribute>
</mbean>

</server>

 

Интересно отметить, как мы внедрили POJO в MBean. Предыдущее продемонстрировало наши первые взаимодействия между различными компонентными моделями.

Чтобы разрешить развертывание MBean через микроконтейнер, нам пришлось написать совершенно новый код обработки модели компонентов. Смотрите system-jmx-beans.xml для более подробной информации. Код из этого файла находится в исходном коде JBossAS : подпроект system-jmx. Одно замечание: в настоящее время это возможно только в реализации JMX JBoss, так как код system-jmx использует некоторые детали реализации.

А что если мы хотим представить наши существующие POJO как MBeans, зарегистрировав их на сервере Mbean?

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="AnnotatedJMXPojo" class="org.jboss.demos.models.jmx.AtJmxPojo"/>

<bean name="XmlJMXPojo" class="org.jboss.demos.models.mbeans.Pojo">
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(exposedInterface=org.jboss.demos.models.mbeans.PojoMBean.class, registerDirectly=true)</annotation>
</bean>

<bean name="ExposedPojo" class="org.jboss.demos.models.jmx.Pojo"/>

<bean name="AnnotatedExposePojo" class="org.jboss.demos.models.jmx.ExposePojo">
<constructor>
<parameter><inject bean="ExposedPojo"/></parameter>
</constructor>
</bean>

</deployment>

 

Как вы можете видеть из любого bean-компонента в этом файле, чтобы представить ваши POJO в качестве MBean-компонентов, нужно просто пометить их аннотацией @JMX. Вы можете либо напрямую выставить бин, либо его свойство:

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="XMLLoginConfig" class="org.jboss.demos.models.old.XMLLoginConfig"/>

<bean name="SecurityConfig" class="org.jboss.demos.models.old.SecurityConfig">
<property name="defaultLoginConfig"><inject bean="XMLLoginConfig"/></property>
</bean>

<bean name="SecurityChecker" class="org.jboss.demos.models.old.Checker">
<property name="loginConfig"><inject bean="jboss.security:service=XMLLoginConfig"/></property>
<property name="securityConfig"><inject bean="jboss.security:service=SecurityConfig"/></property>
</bean>

</deployment>

 

Здесь мы видим, как вы можете использовать любой из типов поиска инъекций, либо просматривая простой POJO, либо получая дескриптор MBean с сервера MBean.

Одним из вариантов впрыска является использование впрыска типа, который также иногда называют автоматическим подключением:

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="FromGuice" class="org.jboss.demos.models.plain.FromGuice">
<constructor><parameter><inject bean="PlainPojo"/></parameter></constructor>
<property name="guicePojo"><inject/></property>
</bean>

<bean name="AllPojos" class="org.jboss.demos.models.plain.AllPojos">
<property name="directMBean"><inject bean="jboss.demos:service=pojo"/></property>
<property name="exposedMBean"><inject bean="jboss.demos:service=ExposedPojo"/></property>
<property name="exposedMBean"><inject bean="jboss.demos:service=ExposedPojo"/></property>
</bean>

</deployment>

 

Bean-компонент FromGuice внедряет bean-компонент Guice посредством сопоставления типов, где PlainPojo внедряется с помощью инъекции общего имени. Затем мы проверяем, работает ли привязка Guice так, как ожидается:

public class FromGuice
{
private IPojo plainPojo;
private org.jboss.demos.models.guice.Pojo guicePojo;

public FromGuice(IPojo plainPojo)
{
this.plainPojo = plainPojo;
}

public void setGuicePojo(org.jboss.demos.models.guice.Pojo guicePojo)
{
this.guicePojo = guicePojo;
}

public void start()
{
f (plainPojo != guicePojo.getMcPojo())
throw new IllegalArgumentException("Pojos are not the same: " + plainPojo + "!=" + guicePojo.getMcPojo());
}
}

 

Это оставляет нам только модель с псевдонимом. Несмотря на то, что псевдоним является довольно тривиальной функцией, чтобы реализовать его как истинную зависимость, его необходимо представить как новую компонентную модель внутри микроконтейнера. Детали реализации этого являются частью исходного кода AbstractController :

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<alias name="SpringPojo">springPojo</alias>

</deployment>

 

Здесь мы сопоставили имя SpringPojo с псевдонимом springPojo. Прелесть наличия псевдонимов в качестве истинных компонентных моделей заключается в том, что не имеет значения, когда будет развернут настоящий бин. Это означает, что псевдоним будет ждать в неустановленном состоянии, пока настоящий бин не вызовет его.

Вывод

Мы видели, как мы можем развертывать простые bean-компоненты Microcontainer, устаревшие MBean-компоненты, POJO Guice, Spring-компоненты и псевдонимы. И поскольку все это контролируется микроконтейнером, мы увидели, как легко мы можем смешивать и сочетать разные модели компонентов.

Я легко могу сказать, что с уровнем абстракции, который мы вкладываем в дизайн нашей компонентной модели, небо — это предел того, с чем мы можем справиться. Примером этого являются готовящиеся сервисы OSGi, но это уже другая история, другая статья.

Следите за моей следующей статьей, которая подробно расскажет о функциональности IoC микроконтейнера .

 

об авторе

Семь лет назад он влюбился в Java и большую часть времени занимался разработкой информационных систем — от обслуживания клиентов до управления энергопотреблением. Он присоединился к JBoss в 2006 году, чтобы полностью посвятить себя работе над проектом Microcontainer, который в настоящее время является его руководителем. Он также участвует в JBoss AS и является специалистом по интеграции Seam и Spring. Он представляет JBoss в группах экспертов «Поддержка динамических компонентов JSR-291 для Java SE» и «OSGi».