Начальная загрузка JPA программно в Java
1. обзор
Большинство приложений, управляемых JPA, активно используют файл“persistence.xml” для получения реализации JPA, напримерHibernate илиOpenJPA.
Наш подход здесьprovides a centralized mechanism for configuring one or more persistence units и связанныйpersistence contexts.
И хотя этот подход не является ошибочным по своей сути, он не подходит для случаев использования, когда необходимо изолированно тестировать компоненты приложения, использующие разные единицы сохранения состояния.
С другой стороны,it’s possible to bootstrap a JPA implementation without resorting to the “persistence.xml” file at all, by just using plain Java.
В этом руководстве мы увидим, как этого добиться с помощью Hibernate.
2. Реализация интерфейсаPersistenceUnitInfo
В типичной конфигурации JPA «на основе xml» реализация JPA автоматически заботится о реализацииPersistenceUnitInfo interface.
Using all the data gathered by parsing the “persistence.xml” file, tпровайдер постоянства использует эту реализацию для создания фабрики менеджеров сущностей. Из этой фабрики мы можем получить менеджера сущностей.
Since we won’t rely on the “persistence.xml” file, the first thing that we need to do is to provide our own PersistenceUnitInfo implementation. Мы будем использовать Hibernate для нашего поставщика постоянства:
public class HibernatePersistenceUnitInfo implements PersistenceUnitInfo {
public static String JPA_VERSION = "2.1";
private String persistenceUnitName;
private PersistenceUnitTransactionType transactionType
= PersistenceUnitTransactionType.RESOURCE_LOCAL;
private List managedClassNames;
private List mappingFileNames = new ArrayList<>();
private Properties properties;
private DataSource jtaDataSource;
private DataSource nonjtaDataSource;
private List transformers = new ArrayList<>();
public HibernatePersistenceUnitInfo(
String persistenceUnitName, List managedClassNames, Properties properties) {
this.persistenceUnitName = persistenceUnitName;
this.managedClassNames = managedClassNames;
this.properties = properties;
}
// standard setters / getters
}
Вкратце, классHibernatePersistenceUnitInfo представляет собой простой контейнер данных, в котором хранятся параметры конфигурации, привязанные к определенной единице сохранения состояния. Это включает в себя имя единицы сохраняемости, имена классов управляемых объектов, тип транзакции, источники данных JTA и не-JTA и т. Д.
3. Создание фабрики Entity Manager с классомEntityManagerFactoryBuilderImpl Hibernate
Теперь, когда у нас есть настраиваемая реализацияPersistenceUnitInfo, последнее, что нам нужно сделать, это создать фабрику диспетчера сущностей.
Hibernate makes this process a breeze, with its EntityManagerFactoryBuilderImpl class (a neat implementation of the builder pattern).
Чтобы обеспечить более высокий уровень абстракции, давайте создадим класс, который объединяет функциональностьEntityManagerFactoryBuilderImpl.
Во-первых, давайте продемонстрируем методы, которые заботятся оcreating an entity manager factory and an entity manager, используя классHibernate’s EntityManagerFactoryBuilderImpl и наш классHibernatePersistenceUnitInfo:
public class JpaEntityManagerFactory {
private String DB_URL = "jdbc:mysql://databaseurl";
private String DB_USER_NAME = "username";
private String DB_PASSWORD = "password";
private Class[] entityClasses;
public JpaEntityManagerFactory(Class[] entityClasses) {
this.entityClasses = entityClasses;
}
public EntityManager getEntityManager() {
return getEntityManagerFactory().createEntityManager();
}
protected EntityManagerFactory getEntityManagerFactory() {
PersistenceUnitInfo persistenceUnitInfo = getPersistenceUnitInfo(
getClass().getSimpleName());
Map configuration = new HashMap<>();
return new EntityManagerFactoryBuilderImpl(
new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration)
.build();
}
protected HibernatePersistenceUnitInfo getPersistenceUnitInfo(String name) {
return new HibernatePersistenceUnitInfo(name, getEntityClassNames(), getProperties());
}
// additional methods
}
Теперь давайте посмотрим наmethods that provide the parameters required by EntityManagerFactoryBuilderImpl and HibernatePersistenceUnitInfo.
Эти параметры включают классы управляемых сущностей, имена классов сущностей, свойства конфигурации Hibernate и объектMysqlDataSource:
public class JpaEntityManagerFactory {
//...
protected List getEntityClassNames() {
return Arrays.asList(getEntities())
.stream()
.map(Class::getName)
.collect(Collectors.toList());
}
protected Properties getProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.id.new_generator_mappings", false);
properties.put("hibernate.connection.datasource", getMysqlDataSource());
return properties;
}
protected Class[] getEntities() {
return entityClasses;
}
protected DataSource getMysqlDataSource() {
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setURL(DB_URL);
mysqlDataSource.setUser(DB_USER_NAME);
mysqlDataSource.setPassword(DB_PASSWORD);
return mysqlDataSource;
}
}
Для простоты мы жестко запрограммировали параметры подключения к базе данных в классеJpaEntityManagerFactory. В производстве, однако, мы должны хранить их в отдельном файле свойств.
Кроме того, методgetMysqlDataSource() возвращает полностью инициализированный объектMysqlDataSource.
Мы сделали это, чтобы упростить отслеживание. В более реалистичном, слабосвязанном дизайне мы бы использовалиinject a DataSource object using EntityManagerFactoryBuilderImpl's withDataSource() method, rather than creating it within the class.
4. Выполнение операций CRUD с помощью Entity Manager
Наконец, давайте посмотрим, как использовать экземплярJpaEntityManagerFactory для получения диспетчера сущностей JPA и выполнения операций CRUD. (Обратите внимание, что для краткости мы опустили классUser):
public static void main(String[] args) {
EntityManager entityManager = getJpaEntityManager();
User user = entityManager.find(User.class, 1);
entityManager.getTransaction().begin();
user.setName("John");
user.setEmail("[email protected]");
entityManager.merge(user);
entityManager.getTransaction().commit();
entityManager.getTransaction().begin();
entityManager.persist(new User("Monica", "[email protected]"));
entityManager.getTransaction().commit();
// additional CRUD operations
}
private static class EntityManagerHolder {
private static final EntityManager ENTITY_MANAGER = new JpaEntityManagerFactory(
new Class[]{User.class})
.getEntityManager();
}
public static EntityManager getJpaEntityManager() {
return EntityManagerHolder.ENTITY_MANAGER;
}
5. Заключение
В этой статье мы показали, как программно запустить диспетчер сущностей JPA с использованием специальной реализации JPAPersistenceUnitInfo interface and Hibernate’s EntityManagerFactoryBuilderImpl class, не полагаясь на традиционный “persistence.xml” file.
Как обычно, доступны все примеры кода, показанные в этой статьеover on GitHub.