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.