我有这个要求在运行时向持久性单元添加实体类,而不是在persistence.xml中指定所有类.有人能帮我一样吗?
我知道Hibernate有自己的相同机制:
AnnotationConfiguration.addAnnotatedClass(Class)等 - 您还可以以*.hbm.xml编程方式添加hibernate config()文件.
要求是,如果不重新启动应用服务器,我应该能够继续动态地将实体类/它们的配置(映射)文件添加到持久性单元.
但是,在运行时以编程方式将实体类/配置文件添加到持久性单元的解决方案不应该特定于JPA实现.
Ste*_*han 31
JPA尚未提供此功能.您可以查看以下三个选项:
以编程方式使用JPA 2.0加载实体类?
关于SO的这个问题与你的相似.一个答案报告说它适用于Spring.
JPA 2.0:自动从不同的jar*中添加实体类到PersistenceUnit*
这里给出了很好的指针.
最后但并非最不重要的,一个简单的解决方法:
1.persistence.xml使用新的持久性单元动态生成(简单的XML文件创建).
2.动态地将持久性文件添加到类路径(URLCLassLoader)
3.要求PersistenceProvider加载新的持久性单元(createEntityManagerFactory)
编辑:
如果JPA提供程序是Hibernate,那么从Hibernate 4.0开始,可以直接将实体传递给这个JPA提供程序,而无需在persistence.xml文件中声明它们.Hibernate将动态处理实体.
编辑:
以下是JPA 2.1 + Hibernate 4.3.7.Final的示例配置,但未声明任何实体:
META-INF/persistence.xml中
<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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"
version="2.1">
<persistence-unit name="my-persistence-unit"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- Database Properties -->
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost:5432/my-database" />
<property name="javax.persistence.jdbc.user" value="login" />
<property name="javax.persistence.jdbc.password" value="password" />
<!-- Hibernate Properties -->
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.default_schema" value="public" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<!-- Connection Pool -->
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="20" />
<property name="hibernate.c3p0.timeout" value="500" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test_period" value="2000" />
</properties>
</persistence-unit>
</persistence>
Run Code Online (Sandbox Code Playgroud)
参考
我迟到了,但我认为这会让一些人头疼.我为纯JPA实现了类路径扫描(不需要弹簧等),如果需要的话也可以与guice-persist集成.
这是你需要做的.
首先,更改persistence.xml并添加您自己的实现,如:
<persistence 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"
version="2.1">
<persistence-unit name="my.persistence.unit" transaction-type="RESOURCE_LOCAL">
<provider>my.custom.package.HibernateDynamicPersistenceProvider</provider>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.max_fetch_depth" value="30" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
Run Code Online (Sandbox Code Playgroud)
为了使提供者得到认可,您必须使其可被发现.JPA发现使用服务加载机制,所以我们添加:
/src/main/resources/META-INF/services/javax.persistence.spi.PersistenceProvider
Run Code Online (Sandbox Code Playgroud)
这个文件只有一行:
my.custom.package.HibernateDynamicPersistenceProvider
Run Code Online (Sandbox Code Playgroud)
最后添加您自己的提供程序并将其基于HibernateProvider(我基于它,因为我想使用hibernate):
public class HibernateDynamicPersistenceProvider extends HibernatePersistenceProvider implements PersistenceProvider {
private static final Logger log = Logger.getLogger(HibernateDynamicPersistenceProvider.class);
public static final String CUSTOM_CLASSES = "CUSTOM_CLASSES";
@Override
protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration, ClassLoader providedClassLoader) {
if(persistenceUnitDescriptor instanceof ParsedPersistenceXmlDescriptor) {
ParsedPersistenceXmlDescriptor tmp = (ParsedPersistenceXmlDescriptor) persistenceUnitDescriptor;
Object object = integration.get("CUSTOM_CLASSES");
}
return super.getEntityManagerFactoryBuilder(persistenceUnitDescriptor, integration, providedClassLoader);
}
protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties, ClassLoader providedClassLoader) {
log.debug( String.format("Attempting to obtain correct EntityManagerFactoryBuilder for persistenceUnitName : %s", persistenceUnitName ));
final Map integration = wrap( properties );
final List<ParsedPersistenceXmlDescriptor> units;
try {
units = PersistenceXmlParser.locatePersistenceUnits( integration );
}
catch (Exception e) {
log.debug( "Unable to locate persistence units", e );
throw new PersistenceException( "Unable to locate persistence units", e );
}
log.debug( String.format("Located and parsed %s persistence units; checking each", units.size() ));
if ( persistenceUnitName == null && units.size() > 1 ) {
// no persistence-unit name to look for was given and we found multiple persistence-units
throw new PersistenceException( "No name provided and multiple persistence units found" );
}
for ( ParsedPersistenceXmlDescriptor persistenceUnit : units ) {
log.debug( String.format(
"Checking persistence-unit [name=%s, explicit-provider=%s] against incoming persistence unit name [%s]",
persistenceUnit.getName(),
persistenceUnit.getProviderClassName(),
persistenceUnitName
));
final boolean matches = persistenceUnitName == null || persistenceUnit.getName().equals( persistenceUnitName );
if ( !matches ) {
log.debug( "Excluding from consideration due to name mis-match" );
continue;
}
// See if we (Hibernate) are the persistence provider
String extractRequestedProviderName = ProviderChecker.extractRequestedProviderName(persistenceUnit, integration);
if ( ! ProviderChecker.isProvider( persistenceUnit, properties ) && !(this.getClass().getName().equals(extractRequestedProviderName))) {
log.debug( "Excluding from consideration due to provider mis-match" );
continue;
}
return getEntityManagerFactoryBuilder( persistenceUnit, integration, providedClassLoader );
}
log.debug( "Found no matching persistence units" );
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
我不得不覆盖2种方法,首先:
protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(
PersistenceUnitDescriptor persistenceUnitDescriptor, Map integration, ClassLoader providedClassLoader)
Run Code Online (Sandbox Code Playgroud)
这是拦截方法.我添加了一个自定义属性"CUSTOM_CLASSES",它应该被称为"CUSTOM_PACKAGES",它将列出所有需要扫描的软件包.在这一点上,我有点懒,我会跳过实际的类路径扫描,但你可以自己做 - 这是非常直接的.然后你可以打电话
tmp.addClasses("class1", "class2");
Run Code Online (Sandbox Code Playgroud)
哪些类是您发现的类.
我们重写的第二种方法是:
protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties, ClassLoader providedClassLoader)
Run Code Online (Sandbox Code Playgroud)
这是因为我们扩展的提供程序是硬编码的,只允许hibernate类创建EMF.由于我们有一个拦截结构的自定义类,我们的名字不会加起来.所以我补充说:
String extractRequestedProviderName = ProviderChecker.extractRequestedProviderName(persistenceUnit, integration);
if ( ! ProviderChecker.isProvider( persistenceUnit, properties ) && !(this.getClass().getName().equals(extractRequestedProviderName))) {
log.debug( "Excluding from consideration due to provider mis-match" );
continue;
}
Run Code Online (Sandbox Code Playgroud)
这扩展了正常的hibernate检查,以使我的自定义提供程序有效.
Wola,我们已经完成了,你现在已经使用JPA进行了hibernate启用的类路径扫描.
| 归档时间: |
|
| 查看次数: |
28041 次 |
| 最近记录: |