Прототип JtaTransactionManager EntityInterceptor Spring/Hibernate

Мы обновляем наше приложение с Spring 3.2.13.RELEASE/Hibernate 3.5.6-Final до Spring 4.3.6.RELEASE/Hibernate 4.2.20.Final-redhat-1.
В Hibernate 3 у нас был HibernateInterceptor, который обладал хорошей функциональностью. Мы использовали этот перехватчик, чтобы установить наш EntityInterceptor (Prototype), открыв новый сеанс.

<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
    <property name="sessionFactory">
        <ref bean="sessionFactory"/>
    </property>
    <property name="entityInterceptorBeanName">
        <value>entityInterceptorName</value> <!--set with BeanFactory  -->
    </property>
</bean> 
<bean id="entityInterceptorName" class="..." scope="prototype" />

В Spring/Hibernate 4 нет эквивалентного класса.
Мы знаем, что HibernateTransactionManager имеет подобную функциональность, но нет возможности установить ее в JtaTransactionManager (что мы на самом деле используем).
Есть ли причина, по которой эти менеджеры транзакций имеют разную функциональность? Есть ли другой способ использовать Entityinterceptor?


person awagenhoffer    schedule 22.06.2017    source источник


Ответы (1)


Мы нашли два обходных пути.
Один из них — определить hibernate.current_session_context_class с нашим классом в SessionFactory. Наш класс устанавливает нашу реализацию JTASessionContext.

<property name="hibernateProperties">
      <props>
          *
        <prop key="hibernate.current_session_context_class">org.path.to.my.context.MySpringSessionContext</prop>
          *
      </props>
 </property>

Собственный контекст сеанса:

public class MySpringSessionContext extends SpringSessionContext {


    public MySpringSessionContext(SessionFactoryImplementor sessionFactory) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
         super(sessionFactory);
         Field transactionManager = this.getClass().getSuperclass().getDeclaredField("transactionManager");
         transactionManager.setAccessible(true);
         Object value = transactionManager.get(this);

         if (value != null) {
             Field jtaSessionContext = this.getClass().getSuperclass().getDeclaredField("jtaSessionContext");
             jtaSessionContext.setAccessible(true);
             jtaSessionContext.set(this, new MySpringJtaSessionContext(sessionFactory));
           }
   }
}

Собственный JTASessionContext:

public class MySpringJtaSessionContext extends SpringJtaSessionContext {

      private BeanFactory beanFactory;
      private String entityInterceptor;

      public MySpringJtaSessionContext(SessionFactoryImplementor factory) {
            super(factory);
            //Ugly but we need Spring
            Interceptor interceptor = factory.getInterceptor();
            if(interceptor instanceof MyBeanFactoryInterceptor){
                this.beanFactory = ((MyBeanFactoryInterceptor) interceptor).getBeanFactory();
                this.entityInterceptor = ((MyBeanFactoryInterceptor) interceptor).getEntityInterceptorBeanName();
            }
       }

       @Override
       protected SessionBuilder baseSessionBuilder() {
          return super.baseSessionBuilder().interceptor(getEntityInterceptor());

      }

    public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
           if (this.beanFactory == null) {
              return EmptyInterceptor.INSTANCE;
           }
           return this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
     }
}

Другой обходной путь: используйте OpenSessionInterceptor (переопределить), но есть и другие трудности (сброс, закрытие сеанса). Но например:

Открыть сеанс с entityinterceptor:

@Override
protected Session openSession() {
    try {
        Session session = getSessionFactory().withOptions().interceptor(getEntityInterceptor()).openSession();
        if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
            session.setFlushMode(FlushMode.MANUAL);
        } else {
            session.setFlushMode(FlushMode.AUTO);
        }
        return session;
    } catch (HibernateException ex) {
        throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
    }
}

Получить перехватчик от Spring:

public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
    if (this.entityInterceptor instanceof String) {
        if (this.beanFactory == null) {
            throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
        }
        return this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
    }
    return (Interceptor) this.entityInterceptor;
}
person awagenhoffer    schedule 16.02.2018