PersistenceAnnotationBeanPostProcessor
是Spring
提供的用于处理注解@PersistenceUnit
和@PersistenceContext
的BeanPostProcessor
。用于注入相应的JPA
资源:EntityManagerFactory
和EntityManager
(或者它们的子类变量)。
注意 : 在目前的实现中,
PersistenceAnnotationBeanPostProcessor
仅仅支持@PersistenceUnit
和@PersistenceContext
上带有属性unitName
或者不带任何属性(比如使用缺省persistence unit
的情况)。如果这些注解使用在类上,并且使用了属性name
,这些注解会被忽略,因为它们此时仅仅作为部署提示(参考Java EE
规范)。
该BeanPostProcessor
从如下渠道获取EntityManagerFactory
对象 :
Spring
应用上下文定义的bean
对象(缺省情况)这种情况下,
EntityManagerFactory
通常由org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
创建。
JNDI
这种情况下,通常会使用
jee:jndi-lookup
XML
配置元素,bean
名称用于匹配被请求的persistence unit
名称。
基于XML
配置时,使用context:annotation-config
或者context:component-scan
时会注册一个缺省的PersistenceAnnotationBeanPostProcessor
。而基于注解的应用,比如Springboot
应用,如果使用了JPA
,应用也会缺省自动注册一个PersistenceAnnotationBeanPostProcessor
。如果你想指定一个自定义的PersistenceAnnotationBeanPostProcessor
的,需要删除或者关闭相应这样的XML
配置或者注解。
Springboot JPA
应用中,PersistenceAnnotationBeanPostProcessor
的注册参考工具类方法AnnotationConfigUtils#registerAnnotationConfigProcessors
:// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); try { def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader())); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex); } def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)); }
bean
的持久化注入元数据开发人员,或者框架自身的某个部分,可能在某些bean
上通过如下方式注入了持久化有关的bean
:
@PersistenceUnit
EntityManagerFactory entityManagerFactory;
@PersistenceContext
EntityManager entityManager;
@PersistenceUnit
public void setEntityManagerFactory(EntityManager entityManagerFactory) {
this.entityManagerFactory= entityManagerFactory;
}
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
对于在bean
上的这些持久化注入的信息,就是由PersistenceAnnotationBeanPostProcessor
来处理的,但是,PersistenceAnnotationBeanPostProcessor
是怎样发现这些信息的呢 ?这一小节,我们来回答这一问题。
首先,PersistenceAnnotationBeanPostProcessor
实现了接口MergedBeanDefinitionPostProcessor
,该接口约定了bean
创建时的生命周期回调方法postProcessMergedBeanDefinition
,该方法会在每个bean
创建过程中,依赖注入进行之前被调用。那么对于PersistenceAnnotationBeanPostProcessor
而言,它的这个方法又做了哪些事情呢 ?
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType,
String beanName) {
// 获取当前被创建的bean的持久化属性元数据
InjectionMetadata metadata = findPersistenceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
上面方法postProcessMergedBeanDefinition
主要逻辑是通过方法findPersistenceMetadata
发现正在创建的bean
的持久化元数据。findPersistenceMetadata
实现如下 :
private InjectionMetadata findPersistenceMetadata(String beanName, final Class<?> clazz,
@Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 从缓存this.injectionMetadataCache中查找针对该bean的持久化元数据,看是否已经获得并缓存,
// 返回 null 的话表示尚未获得和缓存过
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// metadata ==null 的话InjectionMetadata.needsRefresh()会返回true
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 如果 metadata ==null 表明尚未获得和缓存过,
// 此方法在postProcessMergedBeanDefinition里面执行的话显然会走到这里,
// 而在 postProcessProperties 里面执行的话显然不会走到这里
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// 根据 bean class 构建持久化元数据对象 InjectionMetadata ,
// 所使用的 InjectedElement 实现类是 PersistenceElement,
// 一个当前类的内嵌类定义
metadata = buildPersistenceMetadata(clazz);
// 缓存所构建的 InjectionMetadata 对象
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
以上方法findPersistenceMetadata
构建bean
的注解元数据所使用的方法实现如下 :
// 基于类 clazz,使用反射方法获取持久化注解元数据 :
// @PersistenceContext
// @PersistenceUnit
private InjectionMetadata buildPersistenceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements =
new LinkedList<>();
// 使用反射遍历 targetClass 自身声明的各个实例成员属性,看它们是否
// 使用了注解 @PersistenceContext 或者 @PersistenceUnit , 注意,需要忽略
// 类成员属性(也就是使用了 static 修饰符的属性定义)
// 如果遇到了相应的属性,构造一个PersistenceElement对象,添加到currElements
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (field.isAnnotationPresent(PersistenceContext.class) ||
field.isAnnotationPresent(PersistenceUnit.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException(
"Persistence annotations are not supported on static fields");
}
currElements.add(new PersistenceElement(field, field, null));
}
});
// 使用反射遍历 targetClass 自身声明的各个实例成员方法,看它们是否
// 使用了注解 @PersistenceContext 或者 @PersistenceUnit , 注意,
// 1. 需要忽略类成员方法(也就是使用了 static 修饰符的方法定义)
// 2. 使用了以上持久化注解的方法必须只有一个参数
// 3. 也处理因为可能是用泛型导致的桥接方法
// 如果遇到了相应的方法,构造一个PersistenceElement对象,添加到currElements
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if ((bridgedMethod.isAnnotationPresent(PersistenceContext.class) ||
bridgedMethod.isAnnotationPresent(PersistenceUnit.class)) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException(
"Persistence annotations are not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException(
"Persistence annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 注意,这里使用的 InjectedElement 实现类是 PersistenceElement , 这是一个
// PersistenceAnnotationBeanPostProcessor 自定义的专门用于获取和注入持久化属性
// 的 InjectedElement,它是 PersistenceAnnotationBeanPostProcessor 进行持久化
// 属性注入的核心
currElements.add(new PersistenceElement(method, bridgedMethod, pd));
}
});
elements.addAll(0, currElements);
// 处理完 targetClass,开始处理 targetClass 的 父类
targetClass = targetClass.getSuperclass();
}
// 直到 targetClass 变成 null 或者 Object,停止搜寻持久化元数据
while (targetClass != null && targetClass != Object.class);
// 将保存在 elements 中的 PersistenceElement 用于构建针对当前bean的注入元数据对象
// InjectionMetadata
return new InjectionMetadata(clazz, elements);
}
从上面的代码可以看到,PersistenceAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
主要的作用就是提取当前创建的bean
中的持久化属性元数据并保存在this.injectionMetadataCache
中。而对于每个bean
,持久化元数据获取的主要逻辑实现在方法buildPersistenceMetadata
中。而buildPersistenceMetadata
使用了InjectionMetadata
包装针对一个bean
的持久化属性注入元数据,其中的每一条持久化属性注入元数据元素对应一个PersistenceElement
对象。而PersistenceElement
是PersistenceAnnotationBeanPostProcessor
嵌套定义的一个内部类,继承自InjectionMetadata.InjectedElement
。对目标bean
相应持久化属性的注入,主要通过该实现类完成。
从上面的分析我们知道,PersistenceAnnotationBeanPostProcessor
能够获取任何一个bean
上的持久化属性元数据了,也就是说,PersistenceAnnotationBeanPostProcessor
知道针对某个bean
的如下信息 :
那么,这些属性又是如何注入的呢 ? 我们继续分析。
PersistenceAnnotationBeanPostProcessor
又实现了接口InstantiationAwareBeanPostProcessor
约定的生命周期回调方法postProcessProperties
,该方法会在某个bean
创建过程中的属性填充阶段,也可以认为是依赖注入阶段,被应用到该bean
。那么我们来看PersistenceAnnotationBeanPostProcessor
的这个方法又做了哪些事情:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 获取当前bean的持久化属性注入元数据,根据前面的分析,该元数据已经在postProcessMergedBeanDefinition
// 应用阶段获取和缓存,所以这里 metadata 会返回已经缓存的持久化属性注入元数据
InjectionMetadata metadata = findPersistenceMetadata(beanName, bean.getClass(), pvs);
try {
// 根据持久化属性注入元数据执行属性注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of persistence dependencies failed", ex);
}
return pvs;
}
InjectionMetadata#inject
属性注入的过程,主要就是其中每个元素对应的属性注入的执行。而从上面的分析我们已经知道,每个bean
的持久化属性注入元数据对象InjectionMetadata
的每个元素都是一个PersistenceElement
:
/**
* Class representing injection information about an annotated field
* or setter method.
*/
private class PersistenceElement extends InjectionMetadata.InjectedElement {
private final String unitName;
@Nullable
private PersistenceContextType type;
private boolean synchronizedWithTransaction = false;
@Nullable
private Properties properties;
public PersistenceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
PersistenceContext pc = ae.getAnnotation(PersistenceContext.class);
PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class);
Class<?> resourceType = EntityManager.class;
if (pc != null) {
if (pu != null) {
throw new IllegalStateException("Member may only be annotated with either " +
"@PersistenceContext or @PersistenceUnit, not both: " + member);
}
Properties properties = null;
PersistenceProperty[] pps = pc.properties();
if (!ObjectUtils.isEmpty(pps)) {
properties = new Properties();
for (PersistenceProperty pp : pps) {
properties.setProperty(pp.name(), pp.value());
}
}
this.unitName = pc.unitName();
this.type = pc.type();
this.synchronizedWithTransaction =
SynchronizationType.SYNCHRONIZED.equals(pc.synchronization());
this.properties = properties;
}
else {
resourceType = EntityManagerFactory.class;
this.unitName = pu.unitName();
}
checkResourceType(resourceType);
}
/**
* Resolve the object against the application context.
* 从应用上下文中获取要注入的bean实例: EntityManagerFactory 对象或者 EntityManager,
* 覆盖了父类InjectedElement的缺省实现,这是在该类对象上调用#inject方法时,设置目标属性
* 时用于解析对应属性值的方法
*/
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
// Resolves to EntityManagerFactory or EntityManager.
if (this.type != null) {
return (this.type == PersistenceContextType.EXTENDED ?
resolveExtendedEntityManager(target, requestingBeanName) :
resolveEntityManager(requestingBeanName));
}
else {
// OK, so we need an EntityManagerFactory...
return resolveEntityManagerFactory(requestingBeanName);
}
}
// 获取 EntityManagerFactory 的方法
private EntityManagerFactory resolveEntityManagerFactory(@Nullable String requestingBeanName) {
// Obtain EntityManagerFactory from JNDI?
// 从JNDI获取 EntityManagerFactory
EntityManagerFactory emf = getPersistenceUnit(this.unitName);
if (emf == null) {
// Need to search for EntityManagerFactory beans.
// 从 bean 容器获取 EntityManagerFactory
emf = findEntityManagerFactory(this.unitName, requestingBeanName);
}
return emf;
}
// 获取 EntityManager 的方法
private EntityManager resolveEntityManager(@Nullable String requestingBeanName) {
// Obtain EntityManager reference from JNDI?
// 从JNDI获取 EntityManager
EntityManager em = getPersistenceContext(this.unitName, false);
if (em == null) {
// No pre-built EntityManager found -> build one based on factory.
// Obtain EntityManagerFactory from JNDI?
// 从 bean 容器获取 EntityManagerFactory ,然后创建 EntityManager
EntityManagerFactory emf = getPersistenceUnit(this.unitName);
if (emf == null) {
// Need to search for EntityManagerFactory beans.
emf = findEntityManagerFactory(this.unitName, requestingBeanName);
}
// Inject a shared transactional EntityManager proxy.
if (emf instanceof EntityManagerFactoryInfo &&
((EntityManagerFactoryInfo) emf).getEntityManagerInterface() != null) {
// Create EntityManager based on the info's vendor-specific type
// (which might be more specific than the field's type).
em = SharedEntityManagerCreator.createSharedEntityManager(
emf, this.properties, this.synchronizedWithTransaction);
}
else {
// Create EntityManager based on the field's type.
em = SharedEntityManagerCreator.createSharedEntityManager(
emf, this.properties, this.synchronizedWithTransaction, getResourceType());
}
}
return em;
}
// 获取 EntityManager扩展 的方法
private EntityManager resolveExtendedEntityManager(Object target,
@Nullable String requestingBeanName) {
// Obtain EntityManager reference from JNDI?
EntityManager em = getPersistenceContext(this.unitName, true);
if (em == null) {
// No pre-built EntityManager found -> build one based on factory.
// Obtain EntityManagerFactory from JNDI?
EntityManagerFactory emf = getPersistenceUnit(this.unitName);
if (emf == null) {
// Need to search for EntityManagerFactory beans.
emf = findEntityManagerFactory(this.unitName, requestingBeanName);
}
// Inject a container-managed extended EntityManager.
em = ExtendedEntityManagerCreator.createContainerManagedEntityManager(
emf, this.properties, this.synchronizedWithTransaction);
}
if (em instanceof EntityManagerProxy && beanFactory != null && requestingBeanName != null &&
beanFactory.containsBean(requestingBeanName) &&
!beanFactory.isPrototype(requestingBeanName)) {
extendedEntityManagersToClose.put(target, ((EntityManagerProxy)
em).getTargetEntityManager());
}
return em;
}
}
从上面的代码可以看出,持久化属性的注入主要是通过InjectionMetadata#inject
+PersistenceElement#getResourceToInject
完成的。而persistence unit
,persistence context
首先尝试从JDNI
获取,如果获取不到,则尝试从bean
容器获取。下面我们继续分析这些组件的获取方法。
bean
容器获取persistence unit
/persistence context
的方法bean
容器获取persistence unit
protected EntityManagerFactory findEntityManagerFactory(@Nullable String unitName,
@Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
String unitNameForLookup = (unitName != null ? unitName : "");
if (unitNameForLookup.isEmpty()) {
unitNameForLookup = this.defaultPersistenceUnitName;
}
if (!unitNameForLookup.isEmpty()) {
return findNamedEntityManagerFactory(unitNameForLookup, requestingBeanName);
}
else {
return findDefaultEntityManagerFactory(requestingBeanName);
}
}
/**
* Find an EntityManagerFactory with the given name in the current
* Spring application context.
* @param unitName the name of the persistence unit (never empty)
* @param requestingBeanName the name of the requesting bean
* @return the EntityManagerFactory
* @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
*/
protected EntityManagerFactory findNamedEntityManagerFactory(String unitName,
@Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Assert.state(this.beanFactory != null,
"ListableBeanFactory required for EntityManagerFactory bean lookup");
EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory(
this.beanFactory, unitName);
if (requestingBeanName != null && this.beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName,
requestingBeanName);
}
return emf;
}
/**
* Find a single default EntityManagerFactory in the Spring application context.
* @return the default EntityManagerFactory
* @throws NoSuchBeanDefinitionException if there is no single EntityManagerFactory in the context
*/
protected EntityManagerFactory findDefaultEntityManagerFactory(@Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Assert.state(this.beanFactory != null,
"ListableBeanFactory required for EntityManagerFactory bean lookup");
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
// Fancy variant with dependency registration
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory;
NamedBeanHolder<EntityManagerFactory> emfHolder =
clbf.resolveNamedBean(EntityManagerFactory.class);
if (requestingBeanName != null) {
clbf.registerDependentBean(emfHolder.getBeanName(), requestingBeanName);
}
return emfHolder.getBeanInstance();
}
else {
// Plain variant: just find a default bean
return this.beanFactory.getBean(EntityManagerFactory.class);
}
}
bean
容器获取persistence context
从上面的的代码分析可以看出,如果persistence unit
,也就是组件EntityManagerFactory
bean
,是从容器中获取得到的,则persistence context
,也就是EntityManager
实例,会基于该组件EntityManagerFactory
bean
,通过SharedEntityManagerCreator.createSharedEntityManager
方法创建得到。
JNDI
获取persistence unit
/persistence context
的方法JNDI
获取persistence unit
从JNDI
获取persistence unit
的实现由PersistenceAnnotationBeanPostProcessor
实现如下:
@Nullable
protected EntityManagerFactory getPersistenceUnit(@Nullable String unitName) {
if (this.persistenceUnits != null) {
String unitNameForLookup = (unitName != null ? unitName : "");
if (unitNameForLookup.isEmpty()) {
unitNameForLookup = this.defaultPersistenceUnitName;
}
String jndiName = this.persistenceUnits.get(unitNameForLookup);
if (jndiName == null && "".equals(unitNameForLookup) && this.persistenceUnits.size() == 1) {
jndiName = this.persistenceUnits.values().iterator().next();
}
if (jndiName != null) {
try {
return lookup(jndiName, EntityManagerFactory.class);
}
catch (Exception ex) {
throw new IllegalStateException("Could not obtain EntityManagerFactory ["
+ jndiName + "] from JNDI", ex);
}
}
}
return null;
}
JNDI
获取persistence context
从JNDI
获取persistence context
的实现由PersistenceAnnotationBeanPostProcessor
实现如下:
@Nullable
protected EntityManager getPersistenceContext(@Nullable String unitName, boolean extended) {
Map<String, String> contexts = (extended ? this.extendedPersistenceContexts :
this.persistenceContexts);
if (contexts != null) {
String unitNameForLookup = (unitName != null ? unitName : "");
if (unitNameForLookup.isEmpty()) {
unitNameForLookup = this.defaultPersistenceUnitName;
}
String jndiName = contexts.get(unitNameForLookup);
if (jndiName == null && "".equals(unitNameForLookup) && contexts.size() == 1) {
jndiName = contexts.values().iterator().next();
}
if (jndiName != null) {
try {
return lookup(jndiName, EntityManager.class);
}
catch (Exception ex) {
throw new IllegalStateException("Could not obtain EntityManager [" +
jndiName + "] from JNDI", ex);
}
}
}
return null;
}
protected <T> T lookup(String jndiName, Class<T> requiredType) throws Exception {
return new LocatorDelegate().lookup(jndiName, requiredType);
}
LocatorDelegate
– 从JNDI
查找EntityManagerFactory
/EntityManager
// 从JNDI中查找EntityManagerFactory或者EntityManager的内部类,基于JndiLocatorDelegate
// 的一个封装
private class LocatorDelegate {
public <T> T lookup(String jndiName, Class<T> requiredType) throws Exception {
JndiLocatorDelegate locator = new JndiLocatorDelegate();
if (jndiEnvironment instanceof JndiTemplate) {
locator.setJndiTemplate((JndiTemplate) jndiEnvironment);
}
else if (jndiEnvironment instanceof Properties) {
locator.setJndiEnvironment((Properties) jndiEnvironment);
}
else if (jndiEnvironment != null) {
throw new IllegalStateException("Illegal 'jndiEnvironment' type: " +
jndiEnvironment.getClass());
}
locator.setResourceRef(resourceRef);
return locator.lookup(jndiName, requiredType);
}
}
通过上述分析可见,在一个Spring JPA
应用中,PersistenceAnnotationBeanPostProcessor
用于发现每个bean
中的持久化注解并完成这些持久化属性的注入。
这些持久化属性指的是使用@PersistenceUnit
/@PersistenceContext
注解的bean
实例成员属性EntityManagerFactory
/EntityManager
或者这些属性的设置方法。
这个过程发生在每个bean
的创建过程中。具体来讲,持久化属性注入元数据在bean
创建#postProcessMergedBeanDefinition
阶段被获取并缓存在该BeanPostProcessor
对象,在bean
创建#postProcessProperties
阶段被注入到bean
中。
持久化属性的注入使用了框架内部工具InjectionMetadata
+InjectedElement子类PersistenceElement
。该子类PersistenceElement
是一个PersistenceAnnotationBeanPostProcessor
的嵌套子类。
而persistence unit
和persistence context
组件的获取,由PersistenceElement
使用PersistenceAnnotationBeanPostProcessor
提供的方法getPersistenceUnit
/getPersistenceContext
/findEntityManagerFactory
从JNDI
或者bean
容器获得。