Spring BeanPostProcessor : PersistenceAnnotationBeanPostProcessor

概述

PersistenceAnnotationBeanPostProcessorSpring提供的用於處理註解@PersistenceUnit@PersistenceContextBeanPostProcessor。用於註解相應的JPA資源:EntityManagerFactoryEntityManager (或者它們的子類變量)。

注意 : 在目前的實現中,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對象。而PersistenceElementPersistenceAnnotationBeanPostProcessor嵌套定義的一個內部類,繼承自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 unitpersistence 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 unitpersistence context組件的獲取,由PersistenceElement使用PersistenceAnnotationBeanPostProcessor提供的方法getPersistenceUnit/getPersistenceContext/findEntityManagerFactoryJNDI或者bean容器獲得。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章