복붙노트

[SPRING] Spring JPA / Hibernate EmptyInterceptor가 Entitymanager / Spring beans를 주입하지 않음

SPRING

Spring JPA / Hibernate EmptyInterceptor가 Entitymanager / Spring beans를 주입하지 않음

전문가 / 전문가 / 친구

Spring 3.2, JPA 2, Hibernate 4.2 콤보로 작업 중이며, 아래와 같이 구현 된 EmtyInterceptor에 Spring annotated Bean을 주입하려고 할 때 이상한 널 포인터 문제를 직면하게됩니다. 우리는 봄 콩뿐만 아니라이 콩에 주석을 달기를 시도했지만 운은 없다.

이 퍼즐을 해결할 수있는 도움은 매우 높이 평가됩니다.

import javax.inject.Inject;
import javax.inject.Named;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.transaction.annotation.Transactional;
...

@Named
@Transactional
public class AuditEmptyInterceptor extends EmptyInterceptor {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    // Didnt inject - Null
    @PersistenceContext
    private EntityManager entityManager;

    // Didnt inject - Null
    //@PersistenceUnit
    //private EntityManagerFactory entityManagerFactory;

    // Didnt inject - Null
    //@Inject
    //private AuditHelper auditHelper;

    @Override
    public boolean onSave(Object entity, Serializable id, Object[] currentState,
            String[] propertyNames, Type[] types) {

        System.out.println("**********inside OnSave() in Audit Empty Interceptor******************");
        if(entity instanceof xxAuditInterface || entity instanceof xxxCompBranchInterface){
            for (int i = 0; i < propertyNames.length; i++) {
         ...
         ...
         // Null entityManager - NPE here
        javax.persistence.Query query = entityManager.createQuery("Select c From CompanyDO c Where c.companyName =:companyName");
        query.setParameter("companyName", xxx);
        CompanyMasterDO companyMasterDO = (CompanyMasterDO) query.getSingleResult();
         ...
         ...
          }
         }
        }

 }

응용 프로그램의 다른 모든 곳에서 주사는 아무 문제없이 매력처럼 작동합니다. 다음은 applicationContext.xml입니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" 
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">


<context:annotation-config></context:annotation-config> 

<context:component-scan base-package="com" />

<context:property-placeholder location="classpath*:hibernate.properties" />
<tx:annotation-driven />

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com"/>
 </bean>

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/rcent_rel_2"
    p:username="root" p:password="root" />

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter">
    <property name="loadTimeWeaver">
        <bean
            class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="persistenceXmlLocation" value="classpath*:META-INF/spring-persistence.xml" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
    p:entityManagerFactory-ref="entityManagerFactory" />

<bean id="jpaAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
    p:database="MYSQL" 
    p:showSql="false" 
    p:databasePlatform="org.hibernate.dialect.MySQL5Dialect"/>

<\beans>

그리고 우리의 spring-persistence.xml은 아래와 같습니다. Emptyinceptor 속성을 여기에 추가했습니다.

<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="xxx" transaction-type="RESOURCE_LOCAL">
    <class>com.xxx</class>
         ...
         ...
    <properties>
           <property name="hibernate.ejb.interceptor"
                       value="com.company.demo.audit.AuditEmptyInterceptor" />           
    </properties>
    </persistence-unit>
</persistence>

이 문제에 대한 귀하의 소중한 의견이나 조언을 알려주십시오. 다시 한번이 게시물을 읽어 주셔서 감사합니다.

또한 나는 JPA의 Entity Manager를 Hibernate의 EmptyInterceptor에서 주입하는 게시물을 읽었다. 그러나 그들은 수작업으로 이름을 가진 빈을 찾아 내려고 노력하고있는 것처럼 보이고 다른 방법이있을 수 있다고 생각합니다.

해결법

  1. ==============================

    1.AuditEmptyInterceptor는 Spring에 의해 관리되는 Bean이 아니며, Hibernate에 의해 인스턴스화되므로, 의존성을 주입 할 수 없습니다.

    AuditEmptyInterceptor는 Spring에 의해 관리되는 Bean이 아니며, Hibernate에 의해 인스턴스화되므로, 의존성을 주입 할 수 없습니다.

    대신에 정적 위임을 사용할 수 있습니다.

    public class StaticDelegateInterceptor extends EmptyInterceptor {
    
        private static Interceptor interceptor; 
    
        public static void setInterceptor(Interceptor interceptor) {
            StaticDelegate.interceptor = interceptor;
        }
    
        public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
          return StaticDelegate.interceptor.onSave(entity, id, state, propertyNames, types);
        }
        ...
    }
    

    persistence.xml에 StaticDelegateInterceptor를 등록하십시오.

    <persistence>
        <persistence-unit name="xxx" transaction-type="RESOURCE_LOCAL">
           <class>com.xxx</class>
           ...
           ...
           <properties>
              <property name="hibernate.ejb.interceptor"
                       value="com.company.demo.audit.StaticDelegateInterceptor" />           
           </properties>
       </persistence-unit>
    </persistence>
    

    현재 AuditEmptyInterceptor를 수정하여 StaticDelegateInterceptor에 자신을 등록합니다.

    @Named
    @Transactional
    public class AuditEmptyInterceptor extends EmptyInterceptor {  
    
         @PostConstruct
         public void init() {
              StaticDelagateInterceptor.setInterceptor(this);
         }
         ...
    }
    

    마지막으로 entityManagerFactory 빈이 depends-on 속성을 설정하여 auditEmptyInterceptor에 종속되는지 확인하십시오.

    <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter"
    depends-on="auditEmptyInterceptor" >
    ...
    </bean>
    
  2. from https://stackoverflow.com/questions/25274356/spring-jpa-hibernate-emptyinterceptor-not-injecting-entitymanager-spring-beans by cc-by-sa and MIT license