1. Обзор
Это третья из серии статей о постоянстве с весной. Эта статья будет посвящена настройке и реализации Spring с JPA . Пошаговое введение в настройку контекста Spring с использованием конфигурации на основе Java и базового Maven pom для проекта см. В этой статье .
Серия « Стойкость с весны »:
- Часть 1 — Уровень сохраняемости с Spring 3.1 и Hibernate
- Часть 2 — Упрощая уровня доступа к данным с Spring и Java дженериков
- Часть 4 — Уровень сохраняемости с данными Spring JPA
- Часть 5 — конфигурация сделки с JPA и Spring 3.1
2. Больше нет весенних шаблонов
По состоянию на весну 3.1, JpaTemplate и соответствующий JpaDaoSupport были осуждается в пользу использования родного Java Persistence API.
Кроме того, оба эти класса относятся только к JPA 1 (из javadoc JpaTemplate ):
Обратите внимание, что этот класс не был обновлен до JPA 2.0 и никогда не будет обновлен.
Как следствие, в настоящее время рекомендуется использовать непосредственно API персистентности Java вместо JpaTemplate , что эффективно полностью отделит реализацию уровня DAO от Spring.
Исключение перевода без шаблона
Одной из обязанностей JpaTemplate является перевод исключений — перевод исключений низкого уровня — которые связывают API с JPA — в обобщенные исключения Spring более высокого уровня.
Без этого шаблона преобразование исключений можно включить, пометив DAO аннотацией @Repository . Это, в сочетании с постпроцессором bean-компонента Spring, будет советовать всем bean- компонентам @Repository со всеми реализациями PersistenceExceptionTranslator, найденными в контейнере, предоставлять перевод исключений без использования шаблона.
Перевод исключений осуществляется через прокси; чтобы Spring мог создавать прокси вокруг классов DAO, они не должны быть объявлены как final .
Внедрение JPA EntityManager в Spring без шаблона
EntityManager является API контекста постоянства; это может быть введено непосредственно в DAO. Контейнер Spring способен выступать в качестве контейнера JPA и внедрять EntityManager, поддерживая @PersistenceContext (как аннотацию на уровне поля, так и на уровне метода).
Чтобы это работало, bean-компонент PersistenceAnnotationBeanPostProcessor должен существовать в контейнере Spring. Бин может быть создан либо явно, определив его в конфигурации, либо автоматически , определив context: annotation-config или context: component-scan в конфигурации.
3. Конфигурация Spring Java
EntityManager устанавливается в конфигурации путем создания фабрики боб Spring управлять ею; это позволит PersistenceAnnotationBeanPostProcessor получить его из контейнера.
Есть две опции, чтобы установить это — или более простой LocalEntityManagerFactoryBean или более гибкий LocalContainerEntityManagerFactoryBean . Последний вариант используется здесь, так что для него можно настроить дополнительные свойства:
@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setDataSource( this.restDataSource() ); factoryBean.setPackagesToScan( new String[ ] { "org.rest" } ); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(){ { // JPA properties ... } }; factoryBean.setJpaVendorAdapter( vendorAdapter ); factoryBean.setJpaProperties( this.additionlProperties() ); return factoryBean; } @Bean public DataSource restDataSource(){ DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName( this.driverClassName ); dataSource.setUrl( this.url ); dataSource.setUsername( "restUser" ); dataSource.setPassword( "restmy5ql" ); return dataSource; } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( this.entityManagerFactoryBean().getObject() ); return transactionManager; } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){ return new PersistenceExceptionTranslationPostProcessor(); } }
Также обратите внимание, что cglib должен находиться в пути к классам для работы классов Java @Configuration ; Чтобы лучше понять необходимость использования cglib в качестве зависимости, см. эту статью .
4. Конфигурация Spring XML
Та же конфигурация Spring с XML:
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="org.rest" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="${hibernate.show_sql}" /> <property name="generateDdl" value="${jpa.generateDdl}" /> <property name="databasePlatform" value="${persistence.dialect}" /> </bean> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${driverClassName}" /> <property name="url" value="${url}" /> <property name="username" value="restUser" /> <property name="password" value="restmy5ql" /> </bean> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="myEmf" /> </bean> <tx:annotation-driven transaction-manager="txManager" />
Относительно небольшого различия между способом настройки Spring в XML и новой конфигурацией на основе Java — в XML ссылка на другой компонент может указывать либо на компонент, либо на фабрику компонентов для этого компонента. В Java, однако, поскольку типы различаются, компилятор не позволяет этого, и поэтому EntityManagerFactory сначала извлекается из его фабрики компонентов, а затем передается менеджеру транзакций:
txManager.setEntityManagerFactory ( this.entityManagerFactoryBean (). getObject () );
5. Переход на полный XML-менее
Обычно JPA определяет единицу постоянства через файл META-INF / persistence.xml . Начиная с Spring 3.1, этот XML — файл больше не нужен — LocalContainerEntityManagerFactoryBean теперь поддерживает «packagesToScan» свойство , где пакеты для сканирования @Entity классов может быть указан.
Persistence.xml файл был последний кусок XML должен быть удален — теперь, JPA может быть полностью настроен с не XML .
5.1. JPA Свойства
Свойства JPA обычно указываются в файле persistence.xml ; в качестве альтернативы, свойства могут быть указаны непосредственно для фабричного компонента управления объектами:
В качестве дополнительного примечания: если Hibernate будет поставщиком сохраняемости, то это будет способ указать конкретные свойства Hibernate.
5.2. DAO
Каждый DAO будет основан на параметризованном, абстрактном классе класса DAO с поддержкой общих родовых операций:
public abstract class AbstractJpaDAO< T extends Serializable > { private Class< T > clazz; @PersistenceContext EntityManager entityManager; public void setClazz( Class< T > clazzToSet ){ this.clazz = clazzToSet; } public T findOne( Long id ){ return this.entityManager.find( this.clazz, id ); } public List< T > findAll(){ return this.entityManager.createQuery( "from " + this.clazz.getName() ) .getResultList(); } public void save( T entity ){ this.entityManager.persist( entity ); } public void update( T entity ){ this.entityManager.merge( entity ); } public void delete( T entity ){ this.entityManager.remove( entity ); } public void deleteById( Long entityId ){ T entity = this.getById( entityId ); this.delete( entity ); } }
Здесь интересно несколько аспектов — как уже говорилось, абстрактный DAO не расширяет шаблон Spring (такой как JpaTemplate ). Вместо этого JPA EntityManager внедряется непосредственно в DAO и будет выполнять роль основного API постоянства.
Также обратите внимание, что класс сущности передается в конструкторе для использования в общих операциях:
@Repository public class FooDAO extends AbstractHibernateDAO< Foo > implements IFooDAO{ public FooDAO(){ setClazz(Foo.class ); } }
6. Конфигурация Maven
В дополнение к конфигурации Maven, определенной в предыдущей статье , добавлены следующие зависимости: spring-orm (в качестве зависимости также используется spring-tx ) и hibernate-entitymanager :
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.2.0.Final</version> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.24</version> <scope>runtime</scope> </dependency>
Обратите внимание, что зависимость MySQL включена в качестве ссылки — для настройки источника данных необходим драйвер, но подойдет любая база данных, поддерживаемая Hibernate .
7. Заключение
В этой статье рассказывается о настройке и реализации персистентного уровня в JPA 2 и Spring 3.1 с использованием конфигурации на основе XML и Java. Обсуждались причины, по которым мы перестали полагаться на шаблоны для уровня DAO, а также избавились от последнего фрагмента XML, обычно связанного с JPA, — persistence.xml . Конечный результат — легкая, чистая реализация DAO, практически не зависящая от времени компиляции с Spring. Вы можете проверить полную реализацию в проекте github .
Оригинальный слой Persistence с пружиной 3.1 и JPA из серии Persistence with Spring