Статьи

GlassFish 3 за 30 минут

Цель: создать простой проект Java EE 6 на GlassFish v3 в кратчайшие сроки. Проект должен включать в себя: электронную почту, JMS, JPA, web и EJB (сессионный компонент, управляемый сообщениями компонент и компонент времени). Он также должен включать безопасность и транзакции.

Звучит как много, но благодаря Java Enterprise Edition версии 6, настроить проект, подобный этому, и настроить все ресурсы на Сервере приложений стало действительно просто! Я выбрал GlassFish, потому что он имеет открытый исходный код, имеет небольшую полезную консоль администратора и никогда раньше не разрабатывал ее.

Прежде чем начать, я скачал Java SE 6 (обновление 20), Mysql Server, драйвер Mysql JDBC и пакет инструментов GlassFish для Eclipse, который является версией Eclipse 3.5.1 для WTP, с некоторыми конкретными пакетами для разработки и развертывания на GlassFish.

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

Идея заключалась в том, чтобы использовать сервлет для вызова EJB сеанса без сохранения состояния, который сохраняет сообщение с использованием JPA и отправляет сообщение JMS бину, управляемому сообщениями, для асинхронной обработки. MDB отправляет электронное письмо. Таймер EJB обрабатывает и обновляет любые сообщения, которые он находит в базе данных. Кроме того, я установил требование использовать только новейшие технологии в Java EE 6, мой сервлет и компоненты были настроены с использованием аннотаций. Следующая диаграмма последовательности показывает грубый дизайн: Первой задачей было настроить мои ресурсы в GlassFish. Я запустил предустановленный экземпляр сервера, который поставляется с этим специальным Eclipse, и открыл консоль администратора на локальном хосте (получил номер порта из консоли журнала). Не развертывая никаких приложений, я настроил следующее:

нажмите, чтобы увеличить

1) Пулы соединений JDBC, которые содержат сведения о соединении с базой данных — один для данных, другой для области безопасности. При их создании я использовал настройки по умолчанию, кроме:

Пул для данных:

<jdbc-connection-pool datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" res-type="javax.sql.XADataSource" name="testPool" ping="true">

<property name="URL" value="jdbc:mysql://localhost:3306/test" />
<property name="Url" value="jdbc:mysql://localhost:3306/test" />
<property name="User" value="root" />
<property name="Password" value="password" />
.
.
<jdbc-connection-pool>

Пул для Области Безопасности:

  <jdbc-connection-pool driver-classname="com.mysql.jdbc.Driver" res-type="java.sql.Driver" name="realmPool" ping="true">
<property name="URL" value="jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8" />
<property name="password" value="password" />
<property name="user" value="root" />
</jdbc-connection-pool>

2) Ресурсы JDBC, где вы задаете имена JNDI для ваших пулов соединений JDBC.

<jdbc-resource pool-name="testPool" jndi-name="jdbc/test" />   <jdbc-resource pool-name="realmPool" jndi-name="jdbc/realm" />

3) Ресурс JMS — одна фабрика соединений для отправки сообщений и один пункт назначения, представляющий собой очередь, которая ссылается на физический пункт назначения в службе jms (которая автоматически добавляется далее в консоль администратора в рамках службы JMS).

  <admin-object-resource res-adapter="jmsra" res-type="javax.jms.Queue" description="a test queue" jndi-name="jms/destinationResource">
<property name="Name" value="test_destination" />
</admin-object-resource>
<connector-resource pool-name="jmsConnectionPool" jndi-name="jmsConnectionPool" />
<connector-connection-pool name="jmsConnectionPool" resource-adapter-name="jmsra" is-connection-validation-required="true"
connection-definition-name="javax.jms.ConnectionFactory" transaction-support="XATransaction" />

4) Сессия Javamail, чтобы мое приложение могло отправлять электронную почту по протоколу POP3.

<mail-resource host="localhost" store-protocol="POP3" store-protocol-class="com.sun.mail.pop3.POP3Store" jndi-name="mail/Session" from="[email protected]" user="boss">     
<property name="mail-password" value="boss" />
</mail-resource>

5) В разделе «Конфигурация / Безопасность» я настроил область JDBC, которая использовала пул соединений с базой данных области, который был настроен выше.

<auth-realm name="database-realm" classname="com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm">     <property name="jaas-context" value="jdbcRealm" />    
<property name="datasource-jndi" value="jdbc/realm" />
<property name="user-table" value="party" />
<property name="user-name-column" value="login" />
<property name="password-column" value="password" />
<property name="group-table" value="role" />
<property name="group-name-column" value="role" />
<property name="db-user" value="root" />
<property name="db-password" value="password" />
<property name="digest-algorithm" value="none" />
</auth-realm>

 
Вот файл domain.xml (основной файл конфигурации GlassFish, расположенный в папке% glassfishv3_install% / glassfish / domains / domain1 / config, если вы установили сервер, или в папке% GlassFish-Tools-Bundle-For-Eclipse-1.2-Install & / рабочая область / .metadata / .plugins / com.sun.enterprise.jst.server.sunappsrv92 / domain1 / config, если вы установили пакет инструментов GlassFish для Eclipse).

Поместите JAR-файл Mysql J / Connector в папку% GlassFish-Tools-Bundle-For-Eclipse-1.2-Install% / glassfishv3 / glassfish / lib или% glassfishv3_install% \ glassfish \ lib. GlassFish уже содержит JAR-файлы Mail, Activation и JMS на своем пути к классам, поэтому здесь делать больше нечего.

Используя Eclipse, создайте новый проект EAR, а также новый веб-модуль. После создания щелкните правой кнопкой мыши на работающем сервере и нажмите «добавить / удалить». Добавьте новый EAR, чтобы его развернутый и после развертывания вернуться в консоль администратора.

Теперь вы можете настроить виртуальный сервер (хост) так, чтобы вы могли запускать несколько доменов, используя один и тот же сервер (то, что вы могли бы реально захотеть сделать с производственным сервером). Чтобы сделать это, вам нужно либо изменить DNS-сервер, чтобы несколько доменов соответствовали вашему IP-адресу, либо вы можете изменить файл hosts (в windows это c: \ windows \ system32 \ drivers \ etc \ hosts) и добавить домен , В консоли администратора настройте новый виртуальный сервер, ссылаясь на этот домен и установив в качестве приложения по умолчанию то, которое вы только что развернули. Таким образом, любой HTTP-запрос, поступающий для этого домена, отправляется в ваше веб-приложение. Чтобы в вашем приложении можно было перенаправить запрос типа «http: // testwsmaxantcouk: 8084 /» на «index.jsp», необходимо установить корневой контекст веб-приложения на «/» в application.xml или EAR. :

 

<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" id="Application_ID" version="5">
<display-name>Seven
<module>
<web>
<web-uri>SevenWeb.war</web-uri>
<context-root>/</context-root>
</web>
</module>
</application>

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

Следующим шагом является добавление вашего сервлета. Я использовал мастер eclipse для добавления нового сервлета, который генерирует класс в ваш веб-проект с аннотациями Java EE 6:

 @WebServlet(name = "SevenServlet", urlPatterns = { "/SevenServlet" })
public class SevenServlet extends HttpServlet {
.
.

Сервлет делегирует свою работу EJB сеанса без сохранения состояния, который обеспечивает запуск транзакции. EJB также можно использовать для проверки безопасности, хотя сервлет необходимо развернуть в контексте безопасности, чтобы веб-контейнер автоматически отвечал перенаправлением на страницу входа в случае, когда пользователь не вошел в систему. В Java EE 6 вы делаете это также с помощью аннотаций:

@Resource(name="java:app/SevenEJB/EJBSeven")
private EJBSevenLocal ejbLocal;

Когда контейнер находит эту аннотацию в сервлете, он автоматически вставляет EJB.

EJB объявлен с некоторыми аннотациями и ресурсами:

@DeclareRoles({Roles.REGISTERED})
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class EJBSeven implements EJBSevenLocal {
.
.

Это сообщает EJB-контейнеру, что EJB-компонент не имеет состояния, использует управляемые контейнером транзакции и может использоваться пользователями с ролями, «зарегистрированными». Следующие ресурсы объявлены:

@Resource(mappedName = "jms/destinationResource")
private Queue q;

@Resource(mappedName = "jmsConnectionPool")
private QueueConnectionFactory qcf;

@Resource
private SessionContext sessionContext;

@PersistenceContext(unitName="MessageManagement")
private EntityManager em;

Этими ресурсами являются фабрика соединений JMS и очередь для отправки асинхронного сообщения. Контекст сеанса является контекстом сеанса EJB, который, среди прочего, позволяет EJB запрашивать роли пользователей и транзакции отката. Также объявляется JPA Entity Manager, позволяющий EJB использовать базу данных. Наконец, реализован бизнес-метод, объявленный в интерфейсе EJB:

@Override
@RolesAllowed({Roles.REGISTERED})
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public String execute(String command) {
.
.

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

Далее реализуется управляемый сообщениями компонент:

@MessageDriven(
activationConfig = { @ActivationConfigProperty(
propertyName = "destinationType", propertyValue = "javax.jms.Queue"
) },
mappedName = "jms/destinationResource")
public class MDBean implements MessageListener {
.
.

Приведенные выше аннотации сообщают контейнеру, какие сообщения следует отправлять методу onMessage (Message) компонента. У этого компонента также есть ресурсы, а именно почтовый сеанс, для отправки электронной почты:

  @Resource(name="mail/Session")
private Session mailSession;

Таймер EJB также реализован:

 

 @Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class EJBTimerSeven {

@PersistenceContext(unitName="MessageManagement")
private EntityManager em;
.
.

Чтобы bean-компонент таймера мог использовать диспетчер сущностей в транзакционном контексте (чтобы он мог, например, обновлять или вставлять данные), ему также необходимо объявление о том, что он использует транзакции, управляемые контейнером. Метод, который запланирован, определяется следующим образом:

 @Schedule(second="0", minute="*/1", hour="6-23", dayOfWeek="Mon-Fri", dayOfMonth="*", month="*", year="*", info="MyTimer")
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void scheduledTimeout(final Timer t) {
.
.

Обратите внимание, что в этом определении bean-компонента нет ничего, что делало бы его бином таймера. Скорее, метод, который должен вызываться при запуске расписания, просто аннотируется. Я мог бы так же легко добавить этот метод к основному EJB в моем проекте. Шаблон расписания аналогичен планированию задания cron в unix, и вторая часть обеспечения того, что действия этих методов на менеджере сущностей совершаются, состоит в добавлении аннотации TransactionAttribute, в этом случае гарантирующей, что новая транзакция запускается.

Последнее, что мне было нужно, это класс для JPA, представляющий таблицу, в которую я хочу написать:

@Entity
public class Message {

@GeneratedValue(strategy=GenerationType.IDENTITY)
@Id
private int uid;

@Column(name="sender")
private String sender;

@Column(name="when_sent")
private Timestamp whenSent;
.
.

Эти аннотации классов показывают, что это постоянная сущность, использующая JPA (аннотация @Entity), что атрибут «uid» является первичным ключом и генерируется базой данных, а другие атрибуты отображаются на заданные столбцы в базе данных. Используя эти очень простые аннотации и настраивая менеджер сущностей с помощью следующего простого XML, JPA включается, и его становится действительно очень простым в использовании.

<persistence>
<persistence-unit name="MessageManagement">
<jta-data-source>jdbc/test</jta-data-source>
<class>uk.co.maxant.test.Message</class>
</persistence-unit>
</persistence>

Этот XML-файл сохраняется как «persistence.xml» и помещается в папку META-INF проекта EJB.

Итак, настроить корпоративное приложение Java EE 6 очень просто! Вот несколько комментариев …

Помните, что при вызове сервисов (EJB) из вашего веб-уровня (сервлетов или компонентов поддержки JSF) всегда следует вызывать фасад, задачей которого является обеспечение запуска транзакции. Фактически вы могли заметить, что ресурс JDBC области был настроен как простой драйвер SQL, тогда как ресурс JDBC для приложения был настроен как источник данных XA. Какая разница? Хорошо внутри приложения мы использовали JMS и базу данных приложения в одном бизнес-методе нашего EJB, который был запущен в транзакции. Чтобы убедиться, что оба ресурса были зафиксированы вместе или нет, вы ДОЛЖНЫ использовать XA. У фабрики соединений JMS есть флаг, указывающий, что она должна быть с поддержкой XA. Приложение, которое вы можете загрузить в конце этой статьи, содержит гиперссылку для запуска процесса, описанного в верхней части статьи,а также еще одна гиперссылка для запуска с ошибкой. Любые ошибки, возникающие в вашей бизнес-логике до того, как контейнер попытается зафиксировать ресурсы, не затрагиваются XA. Скорее XA помогает, если один из ресурсов не может зафиксировать, скажем, из-за содержания данных, определенных в базе данных. Это означает, что если контейнер отправил сообщение JMS, а затем попытался записать данные в базу данных и обнаружил, что данные недействительны, он не будет фиксировать отправку сообщения JMS, поэтому ни один из ресурсов не будет зафиксирован! Важно понять тонкие различия в том, где происходят ошибки, чтобы увидеть преимущества XA. Для получения дополнительной информации см.XA помогает, если один из ресурсов не может зафиксировать, скажем, из-за содержания данных, определенных в базе данных. Это означает, что если контейнер отправил сообщение JMS, а затем попытался записать данные в базу данных и обнаружил, что данные недействительны, он не будет фиксировать отправку сообщения JMS, поэтому ни один из ресурсов не будет зафиксирован! Важно понять тонкие различия в том, где происходят ошибки, чтобы увидеть преимущества XA. Для получения дополнительной информации см.XA помогает, если один из ресурсов не может зафиксировать, скажем, из-за содержания данных, определенных в базе данных. Это означает, что если контейнер отправил сообщение JMS, а затем попытался записать данные в базу данных и обнаружил, что данные недействительны, он не будет фиксировать отправку сообщения JMS, поэтому ни один из ресурсов не будет зафиксирован! Важно понять тонкие различия в том, где происходят ошибки, чтобы увидеть преимущества XA. Для получения дополнительной информации см.Важно понять тонкие различия в том, где происходят ошибки, чтобы увидеть преимущества XA. Для получения дополнительной информации см.Важно понять тонкие различия в том, где происходят ошибки, чтобы увидеть преимущества XA. Для получения дополнительной информации см.Википедия

Если после развертывания EAR появляется следующая ошибка, не беспокойтесь, это вполне нормально: «WEB9051: Ошибка при попытке сканирования классов в … / eclipseApps / Seven / SevenEJB.jar для аннотаций, в которых выражен ServletContainerInitializer интерес». Смотрите здесь .

Файлы журналов GlassFish можно найти либо в% glassfishv3_install% / glassfish / domains / domain1 / logs, если вы установили сервер, либо в папке% GlassFish-Tools-Bundle-For-Eclipse-1.2-Install & / workspace / .metadata / .plugins /. com.sun.enterprise.jst.server.sunappsrv92 / domain1 / регистрирует, если вы установили пакет инструментов GlassFish для Eclipse).

Если у вас возникают проблемы с областью безопасности, журналы не дают много информации. Самое простое решение — установить точку останова для исключения com.sun.enterprise.security.auth.login.common.LoginException, а когда оно появится, вы можете отладить класс JDBCRealm. Вам необходимо скачать исходный код, который вы можете найти по адресу https://svn.dev.java.net/svn/glassfish-svn/trunk/v3/security/core (вход в систему с пользователем «guest» и без пароля). Более подробную информацию о сфере JDBC можно найти здесь . Еще один примечательный момент, касающийся областей и GlassFish, заключается в том, что в отличие от Tomcat, вы должны указать, какую область использовать в своем веб-приложении. Это можно сделать либо в файле sun-application.xml, либо добавив элемент realm-name в свой элемент login-config файла web.xml. Оба показаны в загрузке для этой статьи (см. Внизу).

До сих пор я никогда не использовал Java EE 6. Я начал использовать простой Spring для простых проектов. Но Java EE 6 практически не отличается от Spring в плане настройки служб (EJB) и добавления аннотаций безопасности и транзакций. Поэтому я начал спрашивать себя, в чем сейчас преимущество Spring. Что ж, Spring по-прежнему предлагает простую обработку базы данных с точки зрения отсутствия необходимости беспокоиться об исключениях и возможности стандартного вызова Hibernate или других сред, но JPA предлагает те же преимущества. Spring также предлагает упрощенную отправку электронной почты, которой нет в Java EE 6, но это не так уж сложно. Приятной особенностью Spring является то, что он включает в себя AOP, который я использовал в основном для улучшения Spring Security (для упрощения поиска в этом блоге для получения более подробной информации) Хотя Java EE 6 не предлагает АОП из коробки,Вы можете добавить его довольно просто (см. http://www.eclipse.org/aspectj). Более того, безопасность, предлагаемая Java EE, намного более стандартна, чем безопасность, предлагаемая Spring. Подводя итог, становится трудно оправдать желание или необходимость использовать Spring. Несмотря на то, что они продаются как легкие, современные серверы приложений Java EE сами по себе довольно легкие, и благодаря «профилям» вы можете получить их версии еще легче. Смотрите java.sun.com для получения дополнительной информации.профили «вы можете получить еще более легкие версии их. См. java.sun.com для получения дополнительной информации.профили «вы можете получить еще более легкие версии их. См. java.sun.com для получения дополнительной информации.

Вы заметите, что имена JNDI, используемые в аннотациях ресурсов в моих EJB-компонентах, были добавлены к атрибутам «mappedName» в аннотациях, а не к «имени». Это означает, что стандартные сопоставления косвенного обращения, которые следует использовать при развертывании EJB, не использовались, а именно ресурс «jms / destinationResource» ДОЛЖЕН присутствовать в дереве JNDI, а не контейнер, ищущий это имя в отображении в дескриптор развертывания. Это хорошо при развертывании ваших собственных EJB-компонентов на вашем собственном сервере приложений, но первоначальная идея создания EJB-компонентов заключалась в том, что вы их напишите, а средство развертывания решит, как называются ресурсы, что, следовательно, требует сопоставления. Если вы делаете сопоставление в дескрипторах развертывания, вам следует использовать атрибут «name» в аннотациях.Смотрите здесьза дополнительной информацией.

Полный исходный код можно скачать здесь .

От http://blog.maxant.co.uk/pebble/2010/05/08/1273354800000.html