Как вы используете Spring Data JPA вне контейнера Spring?

Я пытаюсь подключить объекты JPA Spring Data вручную, чтобы я мог генерировать прокси DAO (также известные как репозитории) - без использования контейнера bean-компонентов Spring.

Меня неизбежно спросят, почему я хочу это сделать: это потому, что наш проект уже использует Google Guice (и в пользовательском интерфейсе с использованием Gin с GWT), и мы не хотим поддерживать другую конфигурацию контейнера IoC, или извлеките все полученные зависимости. Я знаю, что мы могли бы использовать Guice SpringIntegration , но это было бы крайней мерой.

Кажется, что все доступно для подключения объектов вручную, но поскольку это плохо документировано, у меня возникают трудности.

Согласно руководству пользователя Spring Data, использование фабрик репозиториев автономно возможно. К сожалению, в примере показан абстрактный класс RepositoryFactorySupport . После некоторого поиска мне удалось найти JpaRepositoryFactory

JpaRepositoryFactory действительно работает довольно хорошо, за исключением того, что он не создает транзакции автоматически.Транзакциями необходимо управлять вручную, иначе в базе данных ничего не сохранится:

entityManager.getTransaction().begin();
repositoryInstance.save(someJpaObject);
entityManager.getTransaction().commit();

Проблема оказалась в том, что аннотации @Transactional не используются автоматически и требуют помощи TransactionInterceptor

К счастью, JpaRepositoryFactory может принять обратный вызов, чтобы добавить дополнительные рекомендации АОП к сгенерированному прокси-серверу репозитория перед возвратом:

final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
final JpaRepositoryFactory factory = new JpaRepositoryFactory(emf.createEntityManager());

factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
    @Override
    public void postProcess(ProxyFactory factory) {
        factory.addAdvice(new TransactionInterceptor(xactManager, new AnnotationTransactionAttributeSource()));
    }
});

Здесь все не так хорошо. Пройдя через отладчик в коде, TransactionInterceptor действительно создает транзакцию, но на неправильном EntityManager . Spring управляет активным EntityManager , просматривая выполняющийся в данный момент поток. TransactionInterceptor делает это и видит, что с потоком не привязан активный EntityManager , и решает создать новый.

Однако этот новый EntityManager не является тем же экземпляром, который был создан и передан в конструктор JpaRepositoryFactory , для которого требуется EntityManager . Вопрос в том, как мне заставить TransactionInterceptor и JpaRepositoryFactory использовать один и тот же EntityManager ?

Обновление:

При написании этого я выяснили, как решить проблему, но это все еще может быть не идеальным решением. Я отправлю это решение как отдельный ответ. Я был бы рад услышать любые предложения о том, как лучше использовать автономную версию Spring Data JPA, чем то, как я ее решил.

46
задан Oliver Drotbohm 13 September 2017 в 22:29
поделиться