1. Обзор
Большинство приложений, управляемых JPA, интенсивно используют “persistence.xml” файл для получения реализации JPA, такой как Hibernate или OpenJPA .
Наш подход здесь обеспечивает централизованный механизм для настройки одного или нескольких единиц персистентности | и связанных контекстов персистентности .
И хотя этот подход по своей сути не является неправильным, он не подходит для случаев использования, когда необходимо изолированно тестировать компоненты приложения, использующие разные единицы сохранения.
С другой стороны, можно загрузить реализацию JPA, не прибегая к “persistence.xml” файл вообще, просто используя обычную Java .
В этом уроке мы увидим, как это сделать с помощью Hibernate.
2. Реализация интерфейса PersistenceUnitInfo
В типичной конфигурации JPA на основе xml реализация JPA автоматически выполняет реализацию интерфейса PersistenceUnitInfo .
Используя все данные, собранные путем анализа “persistence.xml” file, поставщик сохраняемости t he использует эту реализацию для создания фабрики менеджера сущностей. С этой фабрики мы можем получить менеджера сущностей.
Поскольку мы не будем полагаться на “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 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
} В двух словах, класс HibernatePersistenceUnit Info – это просто обычный контейнер данных, в котором хранятся параметры конфигурации, привязанные к определенному блоку сохранения. Это включает в себя имя единицы сохранения, имена классов управляемых сущностей, тип транзакции, источники данных JTA и не JTA и т. Д.
3. Создание фабрики Entity Manager с классом EntityManagerFactoryBuilderImpl Hibernate
Теперь, когда у нас есть пользовательская реализация PersistenceUnitInfo , последнее, что нам нужно сделать, это получить фабрику менеджера сущностей.
Hibernate делает этот процесс легким, с его классом EntityManagerFactoryBuilderImpl (аккуратная реализация шаблона builder) .
Чтобы обеспечить более высокий уровень абстракции, давайте создадим класс, который обертывает функциональность EntityManagerFactoryBuilderImpl.
Во-первых, давайте продемонстрируем методы , которые заботятся о создании entitymanagerfactory и entitymanager , используя класс EntityManagerFactoryBuilderImpl Hibernate и наш класс HibernatePersistenceUnitInf o:
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
}
Далее давайте рассмотрим методы , которые предоставляют параметры, требуемые EntityManagerFactoryBuilderImpl и HibernatePersistenceUnitInf o .
Эти параметры включают управляемые классы сущностей, имена классов сущностей, свойства конфигурации гибернации и объект 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;
}
}
Для простоты мы жестко закодировали параметры подключения к базе данных в классе Jpa EntityManagerFactory . Однако в процессе производства мы должны хранить их в отдельном файле свойств.
Кроме того, метод get My SqlDataSource() возвращает полностью инициализированный объект MysqlDataSource .
Мы сделали это только для того, чтобы было легко следить за происходящим. В более реалистичном, слабо связанном дизайне мы бы ввели источник данных объект, используя EntityManagerFactoryBuilderImpl’ s withDataSource() метод, а не создавали его в классе .
4. Выполнение Операций CRUD С Менеджером сущностей
Наконец, давайте посмотрим, как использовать экземпляр 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 с помощью пользовательской реализации интерфейса PersistenceUnitInfo JPA и интерфейса EntityManagerFactoryBuilderImpl класса в режиме гибернации , не полагаясь на традиционный “persistence.xml” файл.
Как обычно, все примеры кода, показанные в этой статье, доступны на GitHub.