1 配置和启动时容器和提供者之间的协议
本章定义配置和启动时对Java EE容器和持久化提供者的要求。
1.1 Java EE配置
配置在Java EE容器中的每一个持久化单元有一个persistence.xml文件、任意数量的映射文件和任意数量的类文件组成。
1.1.1 容器的责任
在配置期间容器负责扫描在5.2章节中指定的位置,找到persistence.xml文件并处理它。
当容器找到persistence.xml文件时,它处理它锁包含的持久化单元。容器必须根据persistence_1_0.xsd来验证persistenc.xml并报告所有的错误。没有在persistence.xml中指定的提供者或数据源信息必须在配置时提供或者有容器提供。当为持久化单元创建实体管理器工厂时,容器可以有选择的增加容器特有的属性并传给提供者。
一旦容器读取了持久化元数据,它为每一个配置的命名持久化单元指定javax.persistence.spi.PersistenceProvider实现类。它创建这个实现类的实例并调用这个类的createContainerEntityManagerFactory方法。元数据以PersistneceUnitInfo类的形式作为调用的一部分传递给持久化提供者。容器使用返回的工厂来创建容器管理的试听管理器。对每一个配置的持久化单元配置,只能有一个EntityManagerFactory来创建。从这个给定的工厂可以创建任意数量的实体管理器。
当持久化单元被重新配置时,容器应当调用前一个EntityManagerFactory实例的close方法并且再次使用PersistenceUnitInfo元数据作为参数调用createContainerEntityManagerFactory方法。
1.1.2 持久化提供者的责任
持久化提供者必须实现PersistenceProvider SPI并能够处理传给它的元数据,这些元数据在调用createContainerEntityManagerFactory方法时被传入。使用PersistenceUnitInfo元数据来创建EntityManagerFactory的实例。然后将工厂返回给容器。
持久化提供者处理在持久化单元内的受管理类的元数据注解符。
当持久化提供者获得一个O/R映射文件时,它要处理映射文件包含的定义信息。持久化提供者必须根据orm_1_0.xsd来验证映射信息并报告所有的验证错误。
在Java SE环境下,持久化提供者必须根据persistence_1_0.xsd验证persistence.xml文件并报告所有的验证错误。
1.1.3 Javax.persistence.spi.PersistenceProvider
接口javax.persistence.spi.PersistenceProvider由容器提供者实现。
在Java EE环境下,它被容器调用。在Java SE环境下,它被javax.persistence.Persistence类调用。应用不能使用javax.persistence.spi.PersistenceProvider的实现。
PersistenceProvider类必须有一个public的无参构造器。
在Java SE环境下,在createEntityManagerFactory方法中使用的属性在6.1.3.1章节中作进一步的描述。
package javax.persistence.spi;
/**
* Interface implemented by the persistence provider.
* This interface is used to create an EntityManagerFactory.
* It is invoked by the container in Java EE environments and
* by the Persistence class in Java SE environments.
*/
public interface PersistenceProvider {
/**
* Called by Persistence class when an EntityManagerFactory
* is to be created.
*
* @param emName The name of the persistence unit
* @param map A Map of properties for use by the
* persistence provider. These properties may be used to
* override the values of the corresponding elements in
* the persistence.xml file or specify values for
* properties not specified in the persistence.xml
* (and may be null if no properties are specified).
* @return EntityManagerFactory for the persistence unit,
* or null if the provider is not the right provider
*/
public EntityManagerFactory createEntityManagerFactory(StringemName, Map map);
/**
* Called by the container when an EntityManagerFactory
* is to be created.
*
* @param info Metadata for use by the persistence provider
* @return EntityManagerFactory for the persistence unit
* specified by the metadata
* @param map A Map of integration-level properties for use
* by the persistence provider (may be null if no properties
* are specified).
*/
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map);
}
1.1.3.1持久化单元属性
持久化单元属性放在createEntityManagerFactory(String,Map)方法的Map参数中传递给持久化提供者。这些属性对应于persistence.xml文件中的元素。当在Map中指定这些属性时,它们的值覆盖persistence.xml文件中对应元素的值,也会覆盖提供者可能已经使用的缺省值。
下面列出了本规范定义的属性:
l Javax.persistence.provider——对应于persistence.xml中的provider元素。参见5.2.1.4。
l Javax.persistence.transactionType——对应于persistence.xml中的transaction-type元素。参见5.2.1.2章节。
l Javax.persistence.jtaDataSource——对应于persistence.xml中的jta-data-source元素。参见5.2.1.5章节。
l Javax.persistence.nonJtaDataSource——对应于persistence.xml中的non-jta-data-source元素。参见5.2.1.5章节。
提供商自己的属性也可以包含在map中。提供商必须忽略不能识别的属性。
提供商应当使用自己的属性命名空间(例如:com.acme.persistence.logging)。提供商不能使用javax.persistence及其子空间。javax.persistence命名空间由本规范保留。
1.1.4 Javax.persistence.spi.PersistenceUnitInfo接口
import javax.sql.DataSource;
/**
* Interface implemented by the container and used by the
* persistence provider when creating an EntityManagerFactory.
*/
public interface PersistenceUnitInfo {
/**
* @return The name of the persistence unit.
*Correspondstothenameattributeinthepersistence.xmlfile.
*/
public String getPersistenceUnitName();
/**
* @return The fully qualified name of the persistence provider
* implementation class.
* Corresponds to the <provider> element in the persistence.xml
* file.
*/
public String getPersistenceProviderClassName();
/**
* @return The transaction type of the entity managers created
* by the EntityManagerFactory.
* The transaction type corresponds to the transaction-type
* attribute in the persistence.xml file.
*/
public PersistenceUnitTransactionType getTransactionType();
/**
* @return The JTA-enabled data source to be used by the
* persistence provider.
* The data source corresponds to the <jta-data-source>
* element in the persistence.xml file or is provided at
* deployment or by the container.
*/
public DataSource getJtaDataSource();
/**
* @return The non-JTA-enabled data source to be used by the
* persistence provider for accessing data outside a JTA
* transaction.
*Thedatasourcecorrespondstothenamed<non-jta-data-source>
* element in the persistence.xml file or provided at
* deployment or by the container.
*/
public DataSource getNonJtaDataSource();
/**
* @return The list of mapping file names that the persistence
* provider must load to determine the mappings for the entity
* classes. The mapping files must be in the standard XML
* mapping format, be uniquely named and be resource-loadable
* from the application classpath.
* Each mapping file name corresponds to a <mapping-file>
* element in the persistence.xml file.
*/
public List<String> getMappingFileNames();
/**
* Returns a list of URLs for the jar files or exploded jar
* file directories that the persistence provider must examine
* for managed classes of the persistence unit. Each URL
* corresponds to a named <jar-file> element in the
* persistence.xml file. A URL will either be a file:
* URL referring to a jar file or referring to a directory
* that contains an exploded jar file, or some other URL from
* which an InputStream in jar format can be obtained.
*
* @return a list of URL objects referring to jar files or
* directories.
*/
public List<URL> getJarFileUrls();
/**
* Returns the URL for the jar file or directory that is the
* root of the persistence unit. (If the persistence unit is
* rooted in the WEB-INF/classes directory, this will be the
* URL of that directory.)
* The URL will either be a file: URL referring to a jar file
* or referring to a directory that contains an exploded jar
* file, or some other URL from which an InputStream in jar
* format can be obtained.
*
* @return a URL referring to a jar file or directory.
*/
public URL getPersistenceUnitRootUrl();
/**
* @return The list of the names of the classes that the
* persistence provider must add it to its set of managed
* classes. Each name corresponds to a named <class> element
* in the persistence.xml file.
*/
public List<String> getManagedClassNames();
/**
* @return Whether classes in the root of the persistence
* unit that have not been explicitly listed are to be
* included in the set of managed classes.
* This value corresponds to the <exclude-unlisted-classes>
* element in the persistence.xml file.
*/
public boolean excludeUnlistedClasses();
/**
* @return Properties object. Each property corresponds
* to a <property> element in the persistence.xml file
*/
public Properties getProperties();
/**
* @return ClassLoader that the provider may use to load any
* classes, resources, or open URLs.
*/
public ClassLoader getClassLoader();
/**
* Add a transformer supplied by the provider that will be
* called for every new class definition or class redefinition
* that gets loaded by the loader returned by the
* PersistenceUnitInfo.getClassLoader method. The transformer
* has no effect on the result returned by the
* PersistenceUnitInfo.getNewTempClassLoader method.
*Classesareonlytransformedoncewithinthesameclassloading
* scope, regardless of how many persistence units they may be
* a part of.
*
* @param transformer A provider-supplied transformer that the
* Container invokes at class-(re)definition time
*/
public void addTransformer(ClassTransformer transformer);
/**
* Return a new instance of a ClassLoader that the provider
* may use to temporarily load any classes, resources, or
* open URLs. The scope and classpath of this loader is
* exactly the same as that of the loader returned by
*PersistenceUnitInfo.getClassLoader.Noneoftheclassesloaded
* by this class loader will be visible to application
* components. The provider may only use this ClassLoader
* within the scope of the createContainerEntityManagerFactory
* call.
*
* @return Temporary ClassLoader with same visibility as current
* loader
*/
public ClassLoader getNewTempClassLoader();
}
Theenum javax.persistence.spi.PersistenceUnitTransactionType de?nes
whether the entity managers created by the factory will be JTA or resource-local entity managers.
public enum PersistenceUnitTransactionType {
JTA,
RESOURCE_LOCAL
}
Javax.persistence.spi.ClassTransformer接口由持久化提供者实现,为了提供者能实现在类加载时或在类重定义时转换实体和受管理类。
/**
* A persistence provider supplies an instance of this
* interface to the PersistenceUnitInfo.addTransformer
* method. The supplied transformer instance will get
* called to transform entity class files when they are
* loaded or redefined. The transformation occurs before
* the class is defined by the JVM.
*/
public interface ClassTransformer {
/**
* Invoked when a class is being loaded or redefined.
* The implementation of this method may transform the
* supplied class file and return a new replacement class
* file.
*
* @param loader The defining loader of the class to be
* transformed, may be null if the bootstrap loader
* @param className The name of the class in the internal form
* of fully qualified class and interface names
* @param classBeingRedefined If this is a redefine, the
* class being redefined, otherwise null
* @param protectionDomain The protection domain of the
* class being defined or redefined
* @param classfileBuffer The input byte buffer in class
* file format - must not be modified
* @return A well-formed class file buffer (the result of
* the transform), or null if no transform is performed
* @throws IllegalClassFormatException If the input does
* not represent a well-formed class file
*/
byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException;
}
1.2 在Java SE环境下启动
在Java SE环境下,应用使用Persistence.createEntityManagerFactory方法来创建一个实体管理器工厂(注:在Java EE环境内可以支持使用这些Java SE的启动API;但是不要求支持这种用法)。
提供者配置文件用于暴露提供者实现类给Persistence启动类,把作为候选提供者放在合适的位置以支持命名的持久化单元。
提供者通过创建一个名字为javax.persistence.spi.PersistenceProvider的文本文件并把它放在一个jar文件的META-INF/services目录下来提供提供者配置文件。文件的内容应当是实现了javax.persistence.spi.PersistenceProvider接口的类。
例如:
一个名字为ACME的持久化产品有一个名字为acme.jar的JAR,它包含了持久化提供者的实现。这个JAR包含了提供者配置文件。
acme.jar
META-INF/services/javax.persistence.spi.PersistenceProvider
com.acme.PersistenceProvider
。。。
META-INF/services/javax.persistence.spi.PersistenceProvider文件的内容只有实现类的名字:com.acme.PersistenceProvider。
持久化提供者的jar包和其他服务提供者一样可以用同一种方式安装或者被得到。例如,根据JAR文件规范扩展或者增加到应用的类路径。
Persistence启动类会根据提供者配置文件定位所有的持久化提供者并依次调用他们的createEntityManagerFactory(),直到正确的提供者返回EntityManagerFactory。如果下面的结构返回true,那么提供者就可以认为自己是匹配持久化单元的:
l 它的实现类已经在persistence.xml的provider元素中指定。
l 传入createEntityManagerFactory的Map中包含了javax.persistence.provider属性,并且这个属性的值是提供者的实现类。
l 在persistence.xml或属性map中没有为持久化单元指定提供者。
如果提供者和为命名的持久化单元不匹配,那么它在调用createEntityManagerFactory时必须返回null。
1.2.1 Javax.persistence.Persistence类
package javax.persistence;
import java.util.*;
...
/**
* Bootstrap class that is used to obtain an
* EntityManagerFactory.
*/
public class Persistence {
/**
* Create and return an EntityManagerFactory for the
* named persistence unit.
*
* @param persistenceUnitName The name of the persistence unit
* @return The factory that creates EntityManagers configured
* according to the specified persistence unit
*/
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName) {...}
/**
* Create and return an EntityManagerFactory for the
* named persistence unit using the given properties.
*
* @param persistenceUnitName The name of the persistence unit
* @param props Additional properties to use when creating the
* factory. The values of these properties override any values
* that may have been configured elsewhere.
* @return The factory that creates EntityManagers configured
* according to the specified persistence unit.
*/
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) {...}
...
}