Announcement Announcement Module
Collapse
No announcement yet.
Spring data-JPA's AuditingEntityListener(@Configurable) How does it work? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring data-JPA's AuditingEntityListener(@Configurable) How does it work?

    Hello. i am a developer in asia.

    i can not speak english.
    so with the help of google translator writes a question. please understand.


    Spring data-JPA is the Auditing feature. it operates transparently by AOP are explained.

    Spring data-JPA AuditingEntityListener of the audit information has been processed.
    AuditingEntityListener is AuditorAware need. and @Configurable is declared.
    after you create AuditingEntityListener is AuditorAware injected by spring.

    I've always understood.
    @Configurable in the AspectJ LTW (Load-time weaving) must be present.
    and LTW should use -javaagent option or should use LoadTimeWeaver implementation
    ( ex. TomcatInstrumentableClassLoader )

    but as to write JUnit Test Case. performed without any problems.

    Code:
    - Domain.java
    @Entity
    public class Domain extends AbstractAuditable<User, Long> {
        ...
    }
    
    - User.java
    @Entity
    public class User {
        ...
    }
    
    - DomainRepository.java
    public interface DomainRepository extends JpaRepository<Domain, Long> {
    }
    
    - UserRepository.java
    public interface UserRepository extends JpaRepository<User, Long> {
    }
    
    - DefaultAuditorAware.java
    public class DefaultAuditorAware implements AuditorAware<User> {
        
        @Autowired UserRepository userRepository;
    
        @Override
        public User getCurrentAuditor() {
            return userRepository.findAll().get(0);
        }
    
    }
    
    - orm.xml
    <persistence-unit-metadata>
        <persistence-unit-defaults>
            <entity-listeners>
                <entity-listener class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />
            </entity-listeners>
        </persistence-unit-defaults>
    </persistence-unit-metadata>
    
    - testPersistence-context.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jdbc="http://www.springframework.org/schema/jdbc"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="...">
    
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="packagesToScan" value="test.auditing"/>
            <property name="mappingResources">
                <value>META-INF/orm.xml</value>
            </property>
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
            </property>
            <property name="jpaProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
                    <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
                    <prop key="hibernate.show_sql">false</prop>
                    <prop key="hibernate.format_sql">false</prop>
                </props>
            </property>
        </bean>
        
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"/>
        </bean>
        
        <jdbc:embedded-database id="dataSource" type="HSQL"/>
    
    </beans>
    
    - testRepository-context.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jpa="http://www.springframework.org/schema/data/jpa"
           xsi:schemaLocation="...">
    
        <bean id="auditorAware" class="test.auditing.DefaultAuditorAware" />
    
    	<jpa:repositories base-package="test.auditing" 
    	    entity-manager-factory-ref="entityManagerFactory" 
    	       transaction-manager-ref="transactionManager" />
    
       	<jpa:auditing auditor-aware-ref="auditorAware" />
    
    </beans>
    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"/testPersistence-context.xml", "/testRepository-context.xml"})
    public class NamespaceConfigAuditingTest {
    
        @Autowired UserRepository userRepository;
        @Autowired DomainRepository domainRepository;
        
        @Test
        public void testDomainAuditing() {
            User user = userRepository.saveAndFlush(new User("default"));
            
            Domain domain = domainRepository.save(new Domain());
            
            assertThat(domain.getCreatedBy(), is(user));
        }
    
    }
    without javaagent How does it work?

    and <jpa:auditing/> namespace should be able to track. i found AuditingBeanDefinitionParser.
    modify the test code. performed without any problems.

    the revised code is as follows.

    Code:
    - AuditingBeanDefinitionRegistryPostProcessor.java
    public class AuditingBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
        
        static final String AUDITING_ENTITY_LISTENER_CLASS_NAME = "org.springframework.data.jpa.domain.support.AuditingEntityListener";
        static final String AUDITING_BFPP_CLASS_NAME = "org.springframework.data.jpa.domain.support.AuditingBeanFactoryPostProcessor";
        static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME = "org.springframework.context.config.internalBeanConfigurerAspect";
        static final String BEAN_CONFIGURER_ASPECT_CLASS_NAME = "org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect";
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        }
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            if (!registry.containsBeanDefinition(BEAN_CONFIGURER_ASPECT_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition();
                def.setBeanClassName(BEAN_CONFIGURER_ASPECT_CLASS_NAME);
                def.setFactoryMethodName("aspectOf");
    
                def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                BeanDefinitionReaderUtils.registerBeanDefinition(new BeanComponentDefinition(def, BEAN_CONFIGURER_ASPECT_BEAN_NAME), registry);
            }
            
            BeanDefinitionBuilder builder = rootBeanDefinition(AUDITING_ENTITY_LISTENER_CLASS_NAME);
            builder.setScope("prototype");
            builder.addPropertyValue("auditorAware", createLazyInitTargetSourceBeanDefinition("auditorAware"));
            AbstractBeanDefinition defAel = builder.getRawBeanDefinition();
            BeanDefinitionReaderUtils.registerBeanDefinition(new BeanComponentDefinition(defAel, AUDITING_ENTITY_LISTENER_CLASS_NAME), registry);
            
            RootBeanDefinition defAbepp = new RootBeanDefinition();
            defAbepp.setBeanClassName(AUDITING_BFPP_CLASS_NAME);
            BeanDefinitionReaderUtils.registerBeanDefinition(new BeanComponentDefinition(defAbepp, AUDITING_BFPP_CLASS_NAME), registry);
        }
        
        private BeanDefinition createLazyInitTargetSourceBeanDefinition(String auditorAwareRef) {
            BeanDefinitionBuilder targetSourceBuilder = rootBeanDefinition(LazyInitTargetSource.class);
            targetSourceBuilder.addPropertyValue("targetBeanName", auditorAwareRef);
    
            BeanDefinitionBuilder builder = rootBeanDefinition(ProxyFactoryBean.class);
            builder.addPropertyValue("targetSource", targetSourceBuilder.getBeanDefinition());
    
            return builder.getBeanDefinition();
        }
        
    }
    
    - testRepository-context.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jpa="http://www.springframework.org/schema/data/jpa"
           xsi:schemaLocation="...">
    
        <bean id="auditorAware" class="test.auditing.DefaultAuditorAware" />
    
    	<jpa:repositories base-package="test.auditing" 
    	    entity-manager-factory-ref="entityManagerFactory" 
    	       transaction-manager-ref="transactionManager" />
    
       	<!-- <jpa:auditing auditor-aware-ref="auditorAware" /> -->
    
       	<bean class="test.auditing.AuditingBeanDefinitionRegistryPostProcessor" />
    
    </beans>
    one more test code has been modified.
    three bean(AnnotationBeanConfigurerAspect, AuditingEntityListener, AuditingBeanFactoryPostProcessor) declared in xml.
    tests have failed. I do not know the reason why have failed. help me please.

    Code:
    - testRepository-context.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jpa="http://www.springframework.org/schema/data/jpa"
           xsi:schemaLocation="...">
    
        <bean id="auditorAware" class="test.auditing.DefaultAuditorAware" />
    
    	<jpa:repositories base-package="test.auditing" 
    	    entity-manager-factory-ref="entityManagerFactory" 
    	       transaction-manager-ref="transactionManager" />
    
       	<!-- <jpa:auditing auditor-aware-ref="auditorAware" /> -->
    
       	<!-- <bean class="test.auditing.AuditingBeanDefinitionRegistryPostProcessor" /> -->
    
    	<bean class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf" />
    
        <bean class="org.springframework.data.jpa.domain.support.AuditingEntityListener"
              scope="prototype" 
              abstract="true">
            <property name="auditorAware">
                <bean class="org.springframework.aop.framework.ProxyFactoryBean">
                    <property name="targetSource">
                        <bean class="org.springframework.aop.target.LazyInitTargetSource">
                            <property name="targetBeanName" ref="auditorAware" />
                        </bean>
                    </property>
                </bean>
            </property>
        </bean>
        
        <bean class="org.springframework.data.jpa.domain.support.AuditingBeanFactoryPostProcessor"/>   	
    
    </beans>

  • #2
    up for this one...

    Comment

    Working...
    X