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 ListmanagedClassNames; 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()); Mapconfiguration = 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 ListgetEntityClassNames() { 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.