网上关于jpa的例子很多,今天还是来讲入门,主要在例子中讲解一下各个jpa实现的对比,首先来一个hibernate对于jpa的实现,首先是jpa的配置文件
META-INF下的persist.xml,目前jpa规范中必须是放在这个目录下。
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="jpa"
transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
</properties>
</persistence-unit>
</persistence>
测试代码如下
package org.ww;
import javax.persistence.Persistence;
public class JpaTest {
public static void main(String[] args) {
System.out.println(Persistence.createEntityManagerFactory("jpa"));
}
}
这样虽然会报错,没有配置mysql的driverclass,但是会输出
org.hibernate.ejb.EntityManagerFactoryImpl@16e481a
在这里我们是没有配置provider的,
在persist.xml中provider不是必须配置的,但是如果你的项目中出现多个jpa实现,这时候你想使用哪个provider就必须配置相应的provider,在这里我没有配置provider,但它使用了hibernate,
jpa是PersistenceProviderResolverHolder的CachingPersistenceProviderResolver
private void loadResolverClasses(ClassLoader cl) {
synchronized ( resolverClasses ) {
try {
Enumeration<URL> resources = cl.getResources( "META-INF/services/" + PersistenceProvider.class.getName() );
Set<String> names = new HashSet<String>();
while ( resources.hasMoreElements() ) {
URL url = resources.nextElement();
InputStream is = url.openStream();
try {
names.addAll( providerNamesFromReader( new BufferedReader( new InputStreamReader( is ) ) ) );
}
finally {
is.close();
}
}
for ( String s : names ) {
@SuppressWarnings( "unchecked" )
Class<? extends PersistenceProvider> providerClass = (Class<? extends PersistenceProvider>) cl.loadClass( s );
WeakReference<Class<? extends PersistenceProvider>> reference
= new WeakReference<Class<? extends PersistenceProvider>>(providerClass);
//keep Hibernate atop
if ( s.endsWith( "HibernatePersistence" ) && resolverClasses.size() > 0 ) {
WeakReference<Class<? extends PersistenceProvider>> movedReference = resolverClasses.get( 0 );
resolverClasses.add( 0, reference );
resolverClasses.add( movedReference );
}
else {
resolverClasses.add( reference );
}
}
}
catch ( IOException e ) {
throw new PersistenceException( e );
}
catch ( ClassNotFoundException e ) {
throw new PersistenceException( e );
}
}
}
在这里我们看到是通过查找meta-inf/services/javax.persistence.spi.PersistenceProvider中的内容来使用相应的provider,在hibernate-entitymanager中看到了
查找的是这个provider,在这个provider里面会读取配置persist.xml然后生成entitymanagerFactory
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) {
EntityManagerFactory emf = null;
List<PersistenceProvider> providers = getProviders();
for ( PersistenceProvider provider : providers ) {
emf = provider.createEntityManagerFactory( persistenceUnitName, properties );
if ( emf != null ) {
break;
}
}
if ( emf == null ) {
throw new PersistenceException( "No Persistence provider for EntityManager named " + persistenceUnitName );
}
return emf;
}
这里使用的org.hibernate.ejb.hibernatePersitence作为provider,在createEntityMangeFactory中使用的EJB3Configuration来创建entitymanageFactory,其中有一段代码如下
if ( metadata.getProvider() == null || IMPLEMENTATION_NAME.equalsIgnoreCase(
metadata.getProvider()
) ) {
//correct provider
//lazy load the scanner to avoid unnecessary IOExceptions
Scanner scanner = null;
URL jarURL = null;
if ( metadata.getName() == null ) {
scanner = buildScanner( metadata.getProps(), integration );
jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
metadata.setName( scanner.getUnqualifiedJarName(jarURL) );
}
if ( persistenceUnitName == null && xmls.hasMoreElements() ) {
throw new PersistenceException( "No name provided and several persistence units found" );
}
else if ( persistenceUnitName == null || metadata.getName().equals( persistenceUnitName ) ) {
if (scanner == null) {
scanner = buildScanner( metadata.getProps(), integration );
jarURL = JarVisitorFactory.getJarURLFromURLEntry( url, "/META-INF/persistence.xml" );
}
//scan main JAR
ScanningContext mainJarScanCtx = new ScanningContext()
.scanner( scanner )
.url( jarURL )
.explicitMappingFiles( metadata.getMappingFiles() )
.searchOrm( true );
setDetectedArtifactsOnScanningContext( mainJarScanCtx, metadata.getProps(), integration,
metadata.getExcludeUnlistedClasses() );
addMetadataFromScan( mainJarScanCtx, metadata );
ScanningContext otherJarScanCtx = new ScanningContext()
.scanner( scanner )
.explicitMappingFiles( metadata.getMappingFiles() )
.searchOrm( true );
setDetectedArtifactsOnScanningContext( otherJarScanCtx, metadata.getProps(), integration,
false );
for ( String jarFile : metadata.getJarFiles() ) {
otherJarScanCtx.url( JarVisitorFactory.getURLFromPath( jarFile ) );
addMetadataFromScan( otherJarScanCtx, metadata );
}
return configure( metadata, integration );
}
}
}
}
return null;
在这里,如果xml的provider为空,或者provider不为空但是与自己本身的名字相等则创建entitymanageFactory,否则返回空。只要entityManageFactory创建完成,配置读取就完毕了。
为此,我将多个jpa的实现集成的项目中,EclipseLink,openJpa。如果我的persist.xml中的provider没有写,则默认创建hibernate的provider,然后程序结束,如果xml中写了EclipseLink的provider,则会先执行hibernate,然后执行Eclipselink的provider,然后创建成功。如果配置openjpa的则openjpa的provider是最后一个执行的,这里执行的顺序不固定,在不同的机器上可能不同,但是即使配置了多个jpa,也可以指定想要的jpa实现,唯一的就是实现的效率的问题。也可以不同的persistunit指定不同的jpa实现。