JPA 实体管理器在切入点中为空

发布于 2024-10-24 08:00:57 字数 3429 浏览 2 评论 0原文

我在类中使用 @Aspect 注释定义了切入点。

我使用在上下文中定义的自定义注释来配置切入点:

<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Messaging pointcut -->
<bean id="messagePointcut" class="com.adobe.codex.aspects.MessagePointcut" >
    <constructor-arg ref="msgPointcutEntityFactory"/>   
    <property name="buildDao" ref="buildDao"/>  
</bean>


<!-- enable our own annotation  -->
<aop:config proxy-target-class="true">
    <aop:aspect ref="messagePointcut">
        <aop:pointcut id="proxiedMethods" expression="@annotation(com..codex.aspects.annotation.MessageGateway)"/>
        <aop:around pointcut-ref="proxiedMethods" method="interceptAnnotatedMethod"/>
    </aop:aspect>
</aop:config>

不幸的是,如果我在切入点中有对 buildDao 的引用,则 buildDao 内的entityManager 始终为 null。

不确定解决这个问题的最佳方法是什么。

我假设问题是所使用的编织(加载时间)不知道如何从entityManagerFactory bean 创建entityManager。

这是我的 dao 上下文的片段。

<context:annotation-config /> 
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaProperties">
        <util:properties
            location="classpath:com//codex/dao/jpa/hibernate.properties" />
    </property>
</bean>

<bean id="buildDao" class="com..codex.dao.jpa.JpaBuildDao">
    <description>
        A DAO for Builds.
    </description>
    <property name="queryHelper" ref="queryHelper" />  
    <property name="partDao" ref="partDao" />   
    <property name="buildQueryFactory" ref="buildQueryFactory" />   

</bean>    

这是我的切入点:

@Aspect @事务性() public class MessagePointcut Implements Ordered, MsgObservable {

private   MsgPointcutEntityFactory msgEntityFactory;
private   BuildDao buildDao;


public void setBuildDao(BuildDao buildDao) {
    this.buildDao = buildDao;
}



public MessagePointcut(MsgPointcutEntityFactory msgEntityFactory){
    this.msgEntityFactory = msgEntityFactory;
}

@Transactional(readOnly = true)
public Object interceptAnnotatedMethod(ProceedingJoinPoint pjp) {
    Object returnedEntity = null;
    Object originalEntity = null;



    try { //    

        // do stuff before executing the call
        originalEntity = msgEntityFactory.fetch(id, Build.class);

        //execute the call
        returnedEntity = pjp.proceed();

        // do stuff after executing the call
        // ...

    } catch (Throwable e) {
        e.printStackTrace();
    }
    return returnedEntity;
}

@Override
public int getOrder() {
    return 2;
}

}

的片段

以及我的 dao @Repository 公共类 JpaBuildDao 实现 BuildDao {

private static final Log log = LogFactory.getLog(JpaBuildDao.class);

@PersistenceContext
private EntityManager entityManager;

private QueryHelper queryHelper;
private BuildQueryFactory standardQueryFactory;
private PartDao partDao;

public Build getFlatBuild(Integer id) {
    Build returnBuild;

        Query query = entityManager.createQuery(
                "SELECT b FROM Build b " + 
                "WHERE " +
                "b.id = :id");
        query.setParameter("id", id);
        returnBuild =  (Build) query.getSingleResult();


    return returnBuild;
}

I have defined a pointcut using the @Aspect annotation in my class.

I configure the pointcut using a custom annotation which I have defined in my context:

<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Messaging pointcut -->
<bean id="messagePointcut" class="com.adobe.codex.aspects.MessagePointcut" >
    <constructor-arg ref="msgPointcutEntityFactory"/>   
    <property name="buildDao" ref="buildDao"/>  
</bean>


<!-- enable our own annotation  -->
<aop:config proxy-target-class="true">
    <aop:aspect ref="messagePointcut">
        <aop:pointcut id="proxiedMethods" expression="@annotation(com..codex.aspects.annotation.MessageGateway)"/>
        <aop:around pointcut-ref="proxiedMethods" method="interceptAnnotatedMethod"/>
    </aop:aspect>
</aop:config>

Unfortunately the entityManager inside buildDao is always null if I have a reference to buildDao in my pointcut.

Not sure what the best way to fix this would be.

I'm assuming the problem is that the weaving used (load time) is does not know how to create an entityManager from the entityManagerFactory bean.

here is a snippet of my dao context.

<context:annotation-config /> 
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaProperties">
        <util:properties
            location="classpath:com//codex/dao/jpa/hibernate.properties" />
    </property>
</bean>

<bean id="buildDao" class="com..codex.dao.jpa.JpaBuildDao">
    <description>
        A DAO for Builds.
    </description>
    <property name="queryHelper" ref="queryHelper" />  
    <property name="partDao" ref="partDao" />   
    <property name="buildQueryFactory" ref="buildQueryFactory" />   

</bean>    

Here is my Pointcut:

@Aspect
@Transactional()
public class MessagePointcut implements Ordered, MsgObservable {

private   MsgPointcutEntityFactory msgEntityFactory;
private   BuildDao buildDao;


public void setBuildDao(BuildDao buildDao) {
    this.buildDao = buildDao;
}



public MessagePointcut(MsgPointcutEntityFactory msgEntityFactory){
    this.msgEntityFactory = msgEntityFactory;
}

@Transactional(readOnly = true)
public Object interceptAnnotatedMethod(ProceedingJoinPoint pjp) {
    Object returnedEntity = null;
    Object originalEntity = null;



    try { //    

        // do stuff before executing the call
        originalEntity = msgEntityFactory.fetch(id, Build.class);

        //execute the call
        returnedEntity = pjp.proceed();

        // do stuff after executing the call
        // ...

    } catch (Throwable e) {
        e.printStackTrace();
    }
    return returnedEntity;
}

@Override
public int getOrder() {
    return 2;
}

}

And a snippet of my dao

@Repository
public class JpaBuildDao implements BuildDao {

private static final Log log = LogFactory.getLog(JpaBuildDao.class);

@PersistenceContext
private EntityManager entityManager;

private QueryHelper queryHelper;
private BuildQueryFactory standardQueryFactory;
private PartDao partDao;

public Build getFlatBuild(Integer id) {
    Build returnBuild;

        Query query = entityManager.createQuery(
                "SELECT b FROM Build b " + 
                "WHERE " +
                "b.id = :id");
        query.setParameter("id", id);
        returnBuild =  (Build) query.getSingleResult();


    return returnBuild;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

静待花开 2024-10-31 08:00:57

取得了一些进展。真正的问题是 buildDao 被原始注入到切入点中,没有实例化实体管理器所需的 Jpa 代理。

事实证明,只有当另一个配置细节混入其中时,才会出现此问题。我还有两个 MethodInvokingFactoryBean 实例,将 bean 注入到我的切入点中:

<bean id="registerListenerJms"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <ref local="messagePointcut" />
    </property>
    <property name="targetMethod">
        <value>registerObserver</value>
    </property>
    <property name="arguments">
        <list>
            <ref bean="jmsGateway" />
        </list>
    </property>
</bean>

<bean id="registerListenerAmf"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <ref local="messagePointcut" />
    </property>
    <property name="targetMethod">
        <value>registerObserver</value>
    </property>
    <property name="arguments">
        <list>
            <ref bean="amfGateway" />
        </list>
    </property>
</bean> 

当我删除这两个 bean 时,我的切入点不会获得原始代理,但它会获得一个带有对 dao 引用的 JdkDynamicAopProxy。

不知道为什么 MethodInvokingFactoryBean 会搞乱注入 dao,但确实如此。

最重要的是,我暂时删除了 MethodInvokingFactoryBean,它实现了我的观察者模式,并依赖于要挂接的 bean 上的切入点。

这不是一个完整的解决方案,而是一个可接受的解决方法。

Made some progress. The real issue is that buildDao is injected raw into the pointcut w/o the required Jpa proxy that instantiates the entityManager.

Turns out the issue only occurs when another config detail comes into the mix. I also have two MethodInvokingFactoryBean instances injecting beans into my pointcut:

<bean id="registerListenerJms"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <ref local="messagePointcut" />
    </property>
    <property name="targetMethod">
        <value>registerObserver</value>
    </property>
    <property name="arguments">
        <list>
            <ref bean="jmsGateway" />
        </list>
    </property>
</bean>

<bean id="registerListenerAmf"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <ref local="messagePointcut" />
    </property>
    <property name="targetMethod">
        <value>registerObserver</value>
    </property>
    <property name="arguments">
        <list>
            <ref bean="amfGateway" />
        </list>
    </property>
</bean> 

When I remove these two beans my pointcut doesn't get the raw proxy, but it gets a JdkDynamicAopProxy with a reference to the dao.

Have no clue why MethodInvokingFactoryBean messes up injecting the dao, but it does.

Bottom line is for the time being I'm removing the MethodInvokingFactoryBean that implement my observer pattern and live with a dependency of the pointcut on the beans that want to hook in.

Not a complete solution but an acceptable workaround.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文