Когда мы поставили перед собой цель сертифицировать Java EE 6 Apache Tomcat как Apache TomEE, вот некоторые из пробелов, которые у нас были заполнить, чтобы окончательно сдать Java EE 6 TCK.
Не полный список, но некоторые основные моменты, которые могут быть неочевидными даже при существующих ответах.
Нет TransactionManager
Управление транзакциями обязательно необходимо для любого сертифицированного сервера. В любом веб-компоненте (сервлете, фильтре, слушателе, управляемом компоненте jsf) вы должны иметь возможность ввести UserTransaction следующим образом:
@Resource UserTransaction transaction;
Вы должны иметь возможность использовать javax.transaction.UserTransaction для создания транзакций. Все ресурсы, которых вы касаетесь в рамках этой транзакции, должны быть зарегистрированы в этой транзакции. Сюда входят, помимо прочего, следующие объекты:
javax.sql.DataSource
javax.persistence.EntityManager
javax.jms.ConnectionFactory
javax.jms.QueueConnectionFactory
javax.jms.TopicConnectionFactory
javax.ejb.TimerService
Например, если в сервлете вы запускаете транзакцию, тогда:
- Обновите базу данных
- Отправить сообщение JMS в тему или очередь
- Создайте таймер для работы позже
.. и затем одна из этих вещей не работает, или вы просто решаете вызвать rollback() на UserTransaction, тогда все эти вещи отменяются.
Нет пула подключений
Чтобы быть предельно ясным, существует два типа пула соединений:
- Пул соединений с учетом транзакций
- Пул соединений без поддержки транзакций
Спецификации Java EE строго не требуют создания пула соединений, однако, если у вас есть пул соединений, он должен учитывать транзакции, иначе вы потеряете управление транзакциями.
В основном это означает:
- Все участники одной транзакции должны иметь одно и то же соединение из пула.
- Соединение не должно возвращаться в пул до тех пор, пока транзакция не завершится (фиксация или откат), независимо от того, вызвал ли кто-то
close() или какой-либо другой метод на DataSource.
Распространенной библиотекой, используемой в Tomcat для пула соединений, является commons-dbcp. Мы хотели также использовать это в TomEE, однако он не поддерживал пул соединений с учетом транзакций, поэтому мы фактически добавили эту функциональность в commons-dbcp (yay, Apache), и она присутствует в commons-dbc версии 1.4.
Обратите внимание, что добавления commons-dbcp в Tomcat по-прежнему недостаточно для создания пула транзакционных соединений. Вам по-прежнему нужен диспетчер транзакций, и вам по-прежнему нужен контейнер для регистрации соединений с TransactionManager через Synchronization объектами.
В Java EE 7 говорится о добавлении стандартного способа шифрования паролей БД и их упаковки с приложением в безопасный файл или внешнее хранилище. Это будет еще одна функция, которую Tomcat не будет поддерживать.
Нет интеграции безопасности
Безопасность WebServices, JAX-RS SecurityContext, EJB security, JAAS login и JAAC - все это концепции безопасности, которые по умолчанию не «подключаются» в Tomcat, даже если вы индивидуально добавляете библиотеки, такие как CXF, OpenEJB и т. Д.
Все эти API, конечно, должны работать вместе на сервере Java EE. Нам пришлось немало поработать, чтобы заставить все это взаимодействовать и сделать это поверх Tomcat Realm API, чтобы люди могли использовать все существующие реализации Tomcat Realm для обеспечения своей безопасности «Java EE». Это все еще безопасность Tomcat, просто она очень хорошо интегрирована.
Интеграция с JPA
Да, вы можете поместить поставщика JPA в файл .war и использовать его без помощи Tomcat. При таком подходе вы не получите:
@PersistenceUnit EntityManagerFactory инъекция / поиск
@PersistenceContext EntityManager инъекция / поиск
EntityManager подключен к пулу соединений с поддержкой транзакций
- JTA-Managed
EntityManager поддержка
- Расширенные контексты сохраняемости
JTA-Managed EntityManager в основном означает, что два объекта в одной транзакции, которые хотят использовать EntityManager, будут видеть одно и то же EntityManager, и нет необходимости явно передавать EntityManager. Все это «прохождение» за вас делает контейнер.
Как этого добиться? Просто EntityManager, который вы достали из контейнера, - подделка. Это обертка. Когда вы его используете, он ищет в текущей транзакции реальный EntityManager и делегирует вызов этому EntityManager. Это причина таинственного EntityManager.getDelegate() метода, поэтому пользователи могут получить настоящий EntityManager, если захотят, и использовать любые нестандартные API. Конечно, делайте это с большой осторожностью и никогда не храните ссылку на делегата EntityManager, иначе вы получите серьезную утечку памяти. Делегат EntityManager обычно очищается, закрывается, очищается и отбрасывается после завершения транзакции. Если вы все еще держитесь за ссылку, вы предотвратите сборку мусора для этого EntityManager и, возможно, всех содержащихся в нем данных.
- Всегда безопасно хранить ссылку на
EntityManager, полученную из контейнера.
- Ссылка на
EntityManager.getDelegate() небезопасна.
- Будьте очень осторожны, ссылаясь на
EntityManager, который вы создали сами с помощью EntityManagerFactory - вы на 100% отвечаете за его управление.
Интеграция CDI
Я не хочу чрезмерно упрощать CDI, но я считаю, что он слишком велик, и многие люди не смотрят серьезно - он входит в список «когда-нибудь» для многих :) Итак, вот лишь пара основных моментов, которые Я думаю, что "веб-парень" хотел бы знать об этом.
Вы знаете все, что вам нужно сделать в типичном веб-приложении? Вытаскивать и вынимать вещи HttpSession весь день? Использование String для ключа и непрерывное преобразование объектов, которые вы получаете от HttpSession. Вы, вероятно, использовали служебный код, чтобы сделать это за вас.
У CDI тоже есть этот служебный код, он называется @SessionScoped. Любой объект, помеченный @SessionScoped, помещается и отслеживается в HttpSession для вас. Вы просто запрашиваете внедрение объекта в ваш сервлет через @Inject FooObject, и контейнер CDI будет отслеживать «настоящий» экземпляр FooObject так же, как я описал отслеживание транзакций EntitityManager. Абракадабра, теперь можно удалить кучу кода :)
Делаете какие-нибудь getAttribute и setAttribute на HttpServletRequest? Что ж, вы можете удалить и это с помощью @RequestScoped таким же образом.
И, конечно, есть @ApplicationScoped для устранения вызовов getAttribute и setAttribute, которые вы могли бы делать на ServletContext
Чтобы сделать вещи еще круче, любой объект, отслеживаемый таким образом, может реализовать @PostConstruct, который вызывается при создании bean-компонента, и метод @PreDestroy, который будет уведомлен, когда указанная «область действия» завершена (сеанс завершен, запрос завершен, приложение выключается).
CDI может намного больше, но этого достаточно, чтобы кто-нибудь захотел переписать старое веб-приложение.
Некоторые придирчивые вещи
В Java EE 6 добавлены некоторые вещи, которые не были добавлены в рулевой рубке Tomcats. Они не требуют больших объяснений, но составили большую часть «заполнения пробелов».
- Поддержка
@DataSourceDefinition
- Поддержка Global JNDI (
java:global, java:app, java:module)
- Внедрение Enum через
@Resource MyEnum myEnum и
- Внедрение класса через
@Resource Class myPluggableClass и
- Поддержка
@Resource(lookup="foo")
Незначительные моменты, но может быть невероятно полезно определить DataSource в приложении переносимым способом, обмениваться записями JNDI между веб-приложениями и иметь простую возможность сказать «найдите эту штуку и внедрите ее».
Вывод
Как уже упоминалось, не полный список. Никакого упоминания EJB, JMS, JAX-RS, JAX-WS, JSF, Bean Validation и других полезных вещей. Но по крайней мере некоторое представление о вещах, которые часто упускаются из виду, когда люди говорят о том, что такое Tomcat, а что нет.
Также имейте в виду, что то, что вы могли представить как «Java EE», может не соответствовать фактическому определению. С появлением веб-профиля Java EE сократился. Это было намеренно, чтобы сказать: «Java EE слишком тяжелый, и мне все это не нужно».
Если вы удалите EJB из веб-профиля, вот что у вас останется:
- Сервлеты Java
- Java ServerPages (JSP)
- Java ServerFaces (JSF)
- API транзакций Java (JTA)
- Java Persistence API (JPA)
- Внедрение контекстов и зависимостей Java (CDI)
- Бин-валидация
Это чертовски полезный стек.
person
David Blevins
schedule
08.02.2012