Рубрики
Без рубрики

Программная загрузка JPA на Java

Узнайте, как настроить контекст сохранения JPA в Java без традиционного persistence.xml файл.

Автор оригинала: baeldung.

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.