Glassfish Eclipse Link JPA 按功能打包

Glassfish Eclipse Link JPA Package by feature

我有一个 j2ee 应用程序 运行ning 但我决定将代码组织更改为按功能样式的包而不是我现在使用的按层样式的包,此更改的主要原因是代码导航和模块化,我有这个模式:

我想把它移到:

当我 运行 测试新模式时,一切正常,但是当尝试通过 customerHandler 使用 customerService 时,我收到此错误:

No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call

我尝试将我的 classes 一个一个地分组到新包中,看看哪个是问题所在,当我将这个 class 移到外面时,它是 customerServiceImpl.java com.app.customer 包我的应用程序工作正常,applicationContext.xml 文件配置为扫描 com.app.customer 包,customerDaoImpl 和 customerServiceImpl 有@Transactional 注释,我读到 dao 或服务应该是事务性的,但不是两者兼而有之,所以我尝试从 class 中删除此注释,但我仍然遇到相同的错误。

这是完整的堆栈跟踪:

Warning: StandardWrapperValve[dispatcher]: Servlet.service() for servlet dispatcher threw exception    
javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
        at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:278)
        at com.sun.proxy.$Proxy234.merge(Unknown Source)
        at com.app.customer.customerDaoImpl.merge(customerDaoImpl.java:49)
        at com.app.customer.customerServiceImpl.store(customerServiceImpl.java:69)
        at com.app.customer.customerHandler.store(customerHandler.java:39)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
        at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
        at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
        at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
        at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
        at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:119)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
        at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
        at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
        at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access0(WorkerThreadIOStrategy.java:56)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
        at java.lang.Thread.run(Thread.java:745)

我做错了什么?是否可以通过 eclipselink JPA 使用功能样式的包构建应用程序?

顺便说一句,我可以从数据库中检索客户信息。

编辑:

这是原包装样式的applicationContext.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:p="http://www.springframework.org/schema/p" 
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        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/tx
            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
    <bean id="loadTimeWeaver"  class="org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver" />
    <bean id="entityManagerFactory" p:persistenceUnitName="app_PU"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
    />
    <tx:jta-transaction-manager />
    <tx:annotation-driven />
    <context:annotation-config/> 
    <context:component-scan base-package="com.app.dao"/>
    <context:component-scan base-package="com.app.service"/>
</beans>

对于新的包装风格,我改变了这个:

<context:component-scan base-package="com.app.dao"/>
<context:component-scan base-package="com.app.service"/>

为此:

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

然后我得到上面提到的错误,但是如果我将 customerServiceImpl.class 包外的 com.app.customer 移动到它的原始位置:com.app.service 并将 applicationContext.xml 更改为:

<context:component-scan base-package="com.app.customer"/>
<context:component-scan base-package="com.app.service"/>

我的应用程序有效。

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
                http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="app_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/appDB</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.target-server" value="SunAS9"/>
            <property name="eclipselink.logging.level" value="INFO"/>
        </properties>
    </persistence-unit>
</persistence>

事实证明,当 Controller、Service 和 DAO classes 在同一个包中时,从 Controller 对象到 Service 对象的任何方法调用都被 Spring 视为自身-invocation 调用,这就是为什么没有事务行为被添加到 persist、merge 或 remove 方法的原因,它也解释了为什么当将 ServiceImpl 或 DaoImpl class 移动到不同的包时应用程序工作,因为任何方法都是这样调用被认为是外部调用,将被代理拦截。

通过将事务模式更改为 AOP 解决了问题,这 link 对于配置新的事务模式很有用。