Я пытаюсь подключить объекты Spring Data JPA вручную, чтобы я мог создавать прокси DAO (aka Repositories) - без использования контейнера Spring bean.
Неизбежно, меня спросят, почему я хочу это сделать: это потому, что в нашем проекте уже используется Google Guice (и в пользовательском интерфейсе с использованием Gin с GWT), и мы не хотим поддерживать другую конфигурацию контейнера IoC, или тянуть все результирующие зависимости. Я знаю, что мы могли бы использовать Guice SpringIntegration
, но это было бы последним средством.
Кажется, что все доступно для проводки объектов вручную, но поскольку оно не задокументировано, у меня трудное время.
В соответствии с руководством пользователя Spring Data, использование хранилищ заводов автономно. К сожалению, на примере показан RepositoryFactorySupport
, который является абстрактным классом. После некоторых поисков мне удалось найти JpaRepositoryFactory
JpaRepositoryFactory
действительно работает достаточно хорошо, за исключением того, что он автоматически не создает транзакции. Транзакции должны управляться вручную или ничто не будет сохраняться в базе данных:
entityManager.getTransaction().begin();
repositoryInstance.save(someJpaObject);
entityManager.getTransaction().commit();
Проблема заключалась в том, что аннотации @Transactional
не используются автоматически и нуждаются в помощи a TransactionInterceptor
К счастью, JpaRepositoryFactory
может выполнить обратный вызов для добавления дополнительных советов AOP к сгенерированному прокси-серверу Repository перед возвратом:
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 отдельно, чем то, как я его разрешаю.