最近在做一个web项目. 大系统下有三个子Web模块.
打包时会生成webA.war, webB.war, webC.war.
因为三个子模块有共用的model, 所以我将共有的model层提取到一个公共的模块中:model
系统用maven构建.关系为
parent
|------pom.xml
|------model
|------pom.xml
|------webA
|------pom.xml
|------...META-INF/persistence.xml
|------webB
|------pom.xml
|------...META-INF/persistence.xml
|------webC
|------pom.xml
|------...META-INF/persistence.xml
在抽取共用model模块之前,web中的JPA(Hibernate实现)使用了注解进行entity的声明.
所以persistence.xml的配置很简单:
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}"/>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
</properties>
</persistence-unit>
</persistence>
但在引入公用的包,再运行服务器,会报出"Caused by: org.hibernate.MappingException: Unknown entity: ***"的错误.
经过Google发现,原因是使用Hibernate 如果存在实体在web引用的jar包中,必须在persistence.xml声明这些实体:
<persistence ...> <persistence-unit ...> <class>x.y.z.model.A</class> <class>x.y.z.model.B</class> <class>x.y.z.model.C</class> .... </persistence-unit> </persistence>
但我们的体统中的实体数量并不在少数.有接近100个之多.随着新业务的开发,实体数量还会继续添加.一个一个的声明太过于麻烦.但遗憾的是hibernate在这里并不支持正则表达式.
幸好jpa(hibernate)支持,引入jar. 并在jar中自动查找所有实体,只需要这样声明:
<persistence ...>
<jar-file>classpath:../lib/model.jar</jar-file>
</persistence>
经过这样修改,服务又能正常启动了.
但这样的修改引入了另一个问题. 之前的Junit 集成测试不能使用了.
Junit使用了spring对junit4的注解.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml")
public class XXXIntegrationTest {
@Test
public void testA() {......}
}
不论是在maven下,还是在eclipse中,都会提示java.net.MalformedURLException: unknown protocol: classpath ,而刚才的对persistence.xml的修改正好此入了classpath:..相关的代码.而spring-test的相关类对这样的设置并没有正确的处理. 只有将<jar-file>classpath:../lib/model.jar</jar-file>中的classpath改为开头的file:的路径,spring-test才能正确识别.
所以在测试时,只能将 persistence.xml再改为: <jar-file>file:D:\.m2\repository\...\model.jar<jar-file>才能正确执行.
在打包和测试时,来回修改persistence.xml文件是一件很麻烦的事.只能通过maven的profile来解决了.所以在web模块的pom中加入以下声明.
<project ...>
<properties>
....
<jpa.jar.file>file:${settings.localRepository}/package.../${project.version}/model-${project.version}.jar</jpa.jar.file>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<tasks>
<replace token="@ENTITY-JAR-FILE@" value="${jpa.jar.file}" dir="target/classes/META-INF">
<include name="**/persistence.xml" />
</replace>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profile>
<id>prod</id>
<properties>
<jpa.jar.file>classpath:../lib/model-${project.version}.jar</jpa.jar.file>
</properties>
</profile>
</project>
并在persistence.xml中的jar-file以下修改:
<jar-file>@ENTITY-JAR-FILE@</jar-file>
这样打包和开发就都能顺利进行了.
但回头想想. 解决这个问题还是费了不少时间.
如果一开始直接在persistence.xml定义一串很长的实体列表.虽然看起来比较笨,也不会引入新的问题.其实也挺省时间.
本文介绍了如何在大型Web系统中处理多个子Web模块共享model层时遇到的持久化问题。通过引入通用model模块并利用JPA支持正则表达式的特性,简化了实体类的配置过程。同时,为了方便测试,采用Maven profile动态调整persistence.xml文件,实现了在打包和测试阶段的灵活配置。
181

被折叠的 条评论
为什么被折叠?



