Перейти к основному содержимому

Программная начальная загрузка JPA в Java

· 4 мин. чтения

1. Обзор

Большинство приложений, управляемых JPA, интенсивно используют файл «persistence.xml» для получения реализации JPA, такой как Hibernate или OpenJPA .

Наш подход здесь предоставляет централизованный механизм для настройки одного или нескольких модулей сохраняемости и связанных с ними контекстов сохраняемости .

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

С другой стороны, можно запустить реализацию JPA, вообще не прибегая к файлу «persistence.xml» , просто используя обычную Java .

В этом уроке мы увидим, как это сделать с помощью Hibernate.

2. Реализация интерфейса PersistenceUnitInfo

В типичной конфигурации JPA «на основе XML» реализация JPA автоматически заботится о реализации интерфейса PersistenceUnitInfo .

Используя все данные, собранные при анализе файла «persistence.xml» , поставщик сохраняемости использует эту реализацию для создания фабрики диспетчера сущностей. Из этой фабрики мы можем получить менеджера сущностей.

Поскольку мы не будем полагаться на файл «persistence.xml» , первое, что нам нужно сделать, это предоставить нашу собственную реализацию PersistenceUnitInfo . Мы будем использовать Hibernate для нашего поставщика постоянства:

public class HibernatePersistenceUnitInfo implements PersistenceUnitInfo {

public static String JPA_VERSION = "2.1";
private String persistenceUnitName;
private PersistenceUnitTransactionType transactionType
= PersistenceUnitTransactionType.RESOURCE_LOCAL;
private List<String> managedClassNames;
private List<String> mappingFileNames = new ArrayList<>();
private Properties properties;
private DataSource jtaDataSource;
private DataSource nonjtaDataSource;
private List<ClassTransformer> transformers = new ArrayList<>();

public HibernatePersistenceUnitInfo(
String persistenceUnitName, List<String> 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 упрощает этот процесс благодаря классу EntityManagerFactoryBuilderImpl (аккуратная реализация шаблона Builder) `` .

Чтобы обеспечить более высокий уровень абстракции, давайте создадим класс, обертывающий функциональность EntityManagerFactoryBuilderImpl.

Во-первых, давайте продемонстрируем методы, которые заботятся о создании фабрики диспетчера сущностей и менеджера сущностей , используя класс Hibernate 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<String, Object> configuration = new HashMap<>();
return new EntityManagerFactoryBuilderImpl(
new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration)
.build();
}

protected HibernatePersistenceUnitInfo getPersistenceUnitInfo(String name) {
return new HibernatePersistenceUnitInfo(name, getEntityClassNames(), getProperties());
}

// additional methods
}

Далее рассмотрим методы, предоставляющие параметры, необходимые для EntityManagerFactoryBuilderImpl и HibernatePersistenceUnitInfo .

Эти параметры включают классы управляемых сущностей, имена классов сущностей, свойства конфигурации Hibernate и объект MysqlDataSource :

public class JpaEntityManagerFactory {
//...

protected List<String> 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 .

Мы сделали это только для того, чтобы за всем было легко следить. В более реалистичном, слабосвязанном дизайне мы бы внедрили объект DataSource с помощью метода EntityManagerFactoryBuilderImpl withDataSource () , а не создавали его внутри класса .

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("john@domain.com");
entityManager.merge(user);
entityManager.getTransaction().commit();

entityManager.getTransaction().begin();
entityManager.persist(new User("Monica", "monica@domain.com"));
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, используя пользовательскую реализацию интерфейса JPA PersistenceUnitInfo и класс EntityManagerFactoryBuilderImpl Hibernate , не полагаясь на традиционный файл «persistence.xml» . ``

Как обычно, все примеры кода, показанные в этой статье, доступны на GitHub.