自动注册 java_【技术】JavaSE环境下JPA实体类自动注册

在无容器支持的JavaSE环境下,通常需要在persistence.xml中手动注册JPA实体类。本文介绍了如何利用@Entity注解自动注册实体类,免去手动注册的繁琐。通过继承Eclipselink的PersistenceProvider并覆写createEntityManagerFactoryImpl方法,结合Guava的ClassPath扫描工具,找出带有@Entity注解的类,动态添加到实体类列表中。同时,需在META-INF下创建services/javax.persistence.spi.PersistenceProvider文件,写入自定义的PersistenceProvider以实现自动加载。
摘要由CSDN通过智能技术生成

在没有容器支持的环境下,JPA的实体类(Entity)一般要在persistence.xml中逐个注册,类似下面这样:

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

2

3

4 org.gems.han.security.common.MenuVO

5 org.gems.han.security.common.MenuItemVO

6 org.gems.han.security.common.ModuleVO

7 org.gems.han.security.common.RoleVO

8 org.gems.han.security.common.UserVO

9 org.gems.han.security.common.UserRoleVO

10

11

不知道大家有没有跟我一样感觉很麻烦,也很疑惑,明明每个实体类都标记了@Entity,为什么还要再注册一遍? 有没有办法利用@Entity标记,免除注册实体类的麻烦?经过研究,找到如下方案,分享给大家。

首先说明一下我使用的JPA实现是Eclipselink,我的方案也只在该实现下进行了验证。

我们知道EntityManagerFactory是由PersistenceProvider创建的,就从它入手设法解决上述问题。这个类在不同JPA实现中有不同的实现类,Eclipselink下是org.eclipse.persistence.jpa.PersistenceProvider,我们首先继承这个类,覆盖其中的方法createEntityManagerFactoryImpl,如下:

1 @Override2 protectedEntityManagerFactoryImpl createEntityManagerFactoryImpl(PersistenceUnitInfo puInfo, Map properties,3 booleanrequiresConnection) {4 List classNameList =puInfo.getManagedClassNames();5 List entityClassNameList =getManagedClassNames();6 classNameList.addAll(entityClassNameList);7 return super.createEntityManagerFactoryImpl(puInfo, properties, requiresConnection);8 }

原理说明:第4行,如果persistence.xml中没有注册实体类,那么classNameList将是一个空的List(注意是empty list,不是null);第5行,通过方法getManagedClassNames获取实体类;第6行,把实体类增加到列表中;第7行,调用父类方法,实现工厂类的创建。下面关键就是getManagedClassNames方法的实现。这里我使用了google的开源项目guava来扫描java类,然后从中筛选有@Entity标记的实体类,代码如下:

1 public ListgetManagedClassNames() {2 List managedClassNameList = new ArrayList<>();3 ClassLoader loader =Thread.currentThread().getContextClassLoader();4 ImmutableSet cs = null;5 try{6 cs =ClassPath.from(loader).getTopLevelClasses();7 } catch(IOException e) {8 e.printStackTrace();9 }10 managedClassNameList = new ArrayList<>();11 if (cs != null && cs.isEmpty() == false) {12 for(ClassInfo ci : cs) {13 Class> c = null;14 try{15 c =loader.loadClass(ci.getName());16 } catch(Throwable ex) {17 }18 if (c != null) {19 Entity entity = c.getAnnotation(Entity.class);20 if (entity != null) {21 managedClassNameList.add(c.getName());22 }23 }24 }25 }26 returnmanagedClassNameList;27 }

其中类加载器(loader)根据具体情况使用,但如果使用了特殊的ClassLoader,需要再覆盖org.eclipse.persistence.jpa.PersistenceProvider的getClassLoader方法,以便保证运行时能够正常加载实体类。

另外,在实验中发现PersisitenceProvider是通过SPI的方式加载的,而不是根据配置文件persistence.xml中的设置。因此,需要在META-INF下增加services/javax.persistence.spi.PersistenceProvider文件,在该文件中写入我们自己的PersistenceProvider。这一点我还有些疑惑,请大家在实践中进行验证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值