Главная » Spring » Spring и Java Persistence API

0

С самого начала спецификация EJB включала понятие компонен- тов-сущностей (entity beans). В терминах EJB компонент-сущность представляет собой тип EJB, описывающий прикладные объекты, хранимые в реляционной базе данных. Компоненты-сущности пре- терпели несколько этапов развития на протяжении последних лет, включая появление компонентов-сущностей, которые сами управ- ляют  своим  сохранением  (bean-managed persistence, BMP), и ком-

понентов-сущностей, сохранением которых управляет контейнер

(container-managed persistence, CMP).

Компоненты-сущности пережили взлет и падение популярности EJB. В последние годы разработчики все чаще отказываются от тя- желовесной платформы EJB, отдавая предпочтение реализациям на основе простых POJO. Это явилось серьезной проблемой для ор- ганизации Java Community Process, формировавшей новую специ- фикацию EJB на основе POJO. В итоге появилась спецификация JSR-220, также известная как EJB 3.

На руинах спецификации компонентов-сущностей EJB 2 сформи- ровался новый стандарт хранения данных в JavaJava Persistence API (JPA). JPA представляет собой механизм хранения данных на основе POJO, заимствующий идеи Hibernate и Java Data Objects (JDO) и дополняющий их аннотациями Java 5.

С выходом версии Spring 2.0 состоялась премьера интеграции Spring c JPA. По иронии, многие обвиняют (или приписывают) Spring в упадке EJB. Но теперь, после появления поддержки JPA, многие разработчики рекомендуют использовать в приложениях на основе Spring для работы с базами данных именно JPA. В действи- тельности многие считают, что связка Spring-JPA – это мечта для разработки на основе POJO.

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

Настройка фабрики диспетчера сущностей

Если говорить в двух словах, приложения на основе JPA исполь- зуют реализацию EntityManagerFactory для получения экземпляра EntityManager. Спецификация JPA определяет два вида диспетчеров сущностей (entity managers).

# Управляемые приложением – эти диспетчеры сущностей соз-

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

# Управляемые контейнером – эти диспетчеры сущностей соз- даются и управляются контейнером Java EE. Приложение ни- как не взаимодействует с фабрикой диспетчеров сущностей. Вместо этого диспетчеры сущностей приобретаются прило- жением посредством внедрения или из JNDI. За настройку фабрик диспетчеров сущностей отвечает контейнер. Этот тип диспетчеров сущностей в большей степени подходит для ис- пользования контейнером Java EE, когда требуется обеспечить некоторый контроль над настройками JPA, помимо тех, что определены в файле persistence.xml.

Оба типа диспетчеров сущностей реализуют один и тот же ин- терфейс EntityManager. Но основное отличие заключается не в Entity- Manager как таковом, а скорее в том, как диспетчер создается и управ- ляется. Диспетчеры сущностей, управляемые приложением, созда- ются объектом EntityManagerFactory, полученным вызовом метода createEntityManagerFactory() объекта PersistenceProvider, а диспетчеры сущностей, управляемые контейнером, – вызовом метода create- ContainerEntityManagerFactory().

Так что же все это значит для разработчиков приложений на ос- нове Spring, желающих использовать JPA? В сущности, не так мно- го. Независимо от способа создания EntityManagerFactory, ответствен- ность за управление диспетчерами сущностей будет нести Spring. При использовании диспетчеров сущностей, управляемых приложе- нием, Spring будет играть роль приложения и обеспечит прозрачное управление диспетчерами от имени приложения. В случае исполь- зования диспетчеров сущностей, управляемых контейнером, Spring будет играть роль контейнера.

Каждая фабрика диспетчеров сущностей создается соответствую- щим компонентом Spring:

# LocalEntityManagerFactoryBean создает фабрики EntityManagerFac-

tory, управляемые приложением;

# LocalContainerEntityManagerFactoryBean создает фабрики Entity- ManagerFactory, управляемые контейнером.

Важно отметить, что выбор между фабриками, управляемы- ми приложением и контейнером, полностью прозрачен для при- ложений на основе Spring. Класс JpaTemplate фреймворка Spring полностью скрывает все сложности использования любой из форм EntityManagerFactory, позволяя сосредоточиться в прикладном коде на его основной цели – реализации доступа к данным.

Единственное существенное отличие между ними состоит в том, как они настраиваются в контексте приложения Spring. Рассмотрим для начала, как настроить в Spring компонент LocalEntityManagerFactoryBean фабрики диспетчеров сущностей, управляемых приложением. А за- тем проделаем то же с фабрикой диспетчеров сущностей, управляе- мых контейнером LocalContainerEntityManagerFactoryBean.

Настройка механизма JPA, управляемого приложением

Большая часть настроек фабрики диспетчеров сущностей, управ- ляемых приложением, находится в файле с именем persistence.xml. Этот файл должен находиться в каталоге META-INF, в библиотеке классов.

Назначение файла persistence.xml – определить одну или более единиц хранения. Каждая единица хранения представляет собой группу из одного или более классов хранимых объектов, соответ- ствующих одному источнику данных. То есть в файле persistence. xml перечисляются классы хранимых объектов наряду с дополни- тельными настройками, такими как настройки источников данных и ссылки на XML-файлы отображений. Ниже приводится пример ти- пичного файла persistence.xml, принадлежащего приложению Spitter:

<persistence    xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

<persistence-unit name="spitterPU">

<class>com.habuma.spitter.domain.Spitter</class>

<class>com.habuma.spitter.domain.Spittle</class>

<properties>

<property  name="toplink.jdbc.driver" value="org.hsqldb.jdbcDriver"  />

<property  name="toplink.jdbc.url" value=jdbc:hsqldb:hsql://localhost/spitter/spitter"   />

<property  name="toplink.jdbc.user" value="sa" />

<property   name="toplink.jdbc.password" value="" />

</properties>

</persistence-unit>

</persistence>

Из-за того, что основные настройки сосредоточены в файле persistence.xml, в файле конфигурации Spring требуется (если вооб- ще требуется) указать совсем немного настроек. Следующий элемент

<bean> объявляет компонент LocalEntityManagerFactoryBean в Spring:

<bean  id="emf"

class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">

<property  name="persistenceUnitName"  value="spitterPU"  />

</bean>

Значение, указанное в свойстве persistenceUnitName, ссылается на имя единицы хранения, объявленной в файле persistence.xml.

Причина, почему большая часть настроек создания фабрик EntityManagerFactory диспетчеров сущностей, управляемых приложе- нием, сосредоточена в файле persistence.xml, обусловлена стремле- нием переместить в него все, что связано с созданием фабрик. При использовании сущностей, управляемых приложением (без привле- чения фреймворка Spring), полную ответственность за получение фабрики EntityManagerFactory через реализацию PersistenceProvider несет само приложение. Код приложения окажется невероятно раз- дутым, если будет определять единицы хранения при каждой попыт- ке получить объект EntityManagerFactory. При наличии же настроек в файле persistence.xml механизм JPA сможет без труда отыскать определения единиц хранения в известном месте.

Однако благодаря поддержке JPA в Spring вам никогда не при- дется напрямую работать с PersistenceProvider. Поэтому кажется бессмысленным  перемещение  конфигурационной  информации в файл persistence.xml. Фактически это препятствует определению настроек EntityManagerFactory в конфигурации Spring (чтобы, напри- мер, определить источник данных, настраиваемый фреймворком Spring).

Поэтому имеет смысл обратить внимание на механизм JPA, управ- ляемый контейнером.

Настройка механизма JPA, управляемого контейнером

Настройка механизма JPA, управляемого контейнером, предпо- лагает несколько иной подход. При выполнении в пределах кон- тейнера EntityManagerFactory может быть создан на основе информа- ции, предоставляемой контейнером, в данном случае – контейнером Spring.

Вместо настройки источника данных в файле persistence.xml не- обходимую информацию можно определить в контексте приложе- ния Spring. Например, следующее объявление элемента <bean> де- монстрирует, как настроить в Spring механизм JPA, управляемый контейнером, используя LocalContainerEntityManagerFactoryBean.

<bean  id="emf"  class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />

</bean>

Здесь в свойство dataSource внедряется ссылка на источник данных, настраиваемый в конфигурации Spring. В данном случае можно использовать любую реализацию javax.sql.DataSource, на- пример реализацию, настроенную в разделе 6.2. Источник данных все еще может настраиваться в persistence.xml, однако источник данных, определяемый через это свойство, имеет более высокий приоритет.

Свойство jpaVendorAdapter может быть использовано для настрой- ки особенностей конкретной реализации JPA. В состав Spring входят несколько классов адаптеров JPA:

# EclipseLinkJpaVendorAdapter;

# HibernateJpaVendorAdapter;

# OpenJpaVendorAdapter;

# TopLinkJpaVendorAdapter.

В данном случае использована JPA-реализация для Hibernate, по- этому настройки выполняются с применением HibernateJpaVendorAdapter:

<bean   id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

<property  name="database"  value="HSQL"  />

<property name="showSql" value="true"/>

<property  name="generateDdl"  value="false"/>

<property  name="databasePlatform"

value="org.hibernate.dialect.HSQLDialect"  />

</bean>

Таблица 6.5. Адаптер Hibernate JPA поддерживает несколько типов баз данных. Определить тип базы данных можно настройкой его свойства

База данных

Значение для свойства database

IBM DB2

DB2

Apache Derby

DERBY

H2

H2

Hypersonic

HSQL

Таблица 6.5 (окончание)

База данных

Значение для свойства database

Informix

INFORMIX

MySQL

MYSQL

Oracle

ORACLE

PostgreSQL

POSTGRESQL

Microsoft SQL Server

SQLSERVER

Sybase

SYBASE

Адаптер имеет несколько свойств, доступных для настройки, но наиболее важным из них является свойство database, где в данном примере определен тип используемой базы данных – Hypersonic. Другие значения, поддерживаемые этим свойством, перечислены в табл. 6.5.

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

Выбор того или иного компонента фабрики диспетчеров сущно- стей зависит в первую очередь от того, как он будет использоваться. Для простых приложений достаточно будет использовать LocalEntit yManagerFactoryBean. Но, поскольку LocalContainerEntityManagerFactoryBe an обеспечивает более широкие возможности настройки механизма JPA в Spring, он выглядит более привлекательно, и вы наверняка предпочтете использовать именно его в своих приложениях.

Получение EntityManagerFactory из JNDI

Следует также отметить, что при развертывании приложения на основе Spring на некоторых серверах приложений компонент EntityManagerFactory уже может быть создан автоматически и нахо- диться в JNDI, ожидая, пока его извлекут. В этом случае для полу- чения ссылки на EntityManagerFactory  можно использовать элемент

<jee:jndilookup> из пространства имен jee:

<jee:jndi-lookup  id="emf"  jndi-name="persistence/spitterPU"  />

Независимо от того, как будет получен компонент EntityManager- Factory, после его приобретения можно приступать к созданию клас- сов DAO. Сделаем это прямо сейчас.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии