SpringDataJPA+Hibernate框架源码剖析(六)@PersistenceContext和@Autowired注入EntityManager的区别

SpringDataJPA+Hibernate框架源码剖析系列文章:

  1. SpringDataJPA+Hibernate框架源码剖析(一)框架介绍
  2. SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建
  3. SpringDataJPA+Hibernate框架源码剖析(三)框架整合 之 Repository接口实现的生成
  4. SpringDataJPA+Hibernate框架源码剖析(四)框架整合 之 事务管理器的构建(包括spring的事务机制)
  5. SpringDataJPA+Hibernate框架源码剖析(五)框架整合 之 SpringBoot整合JPA剖析
  6. SpringDataJPA+Hibernate框架源码剖析(六)@PersistenceContext和@Autowired注入EntityManager的区别

很多人应该遇到过@Autowired注入EntityManager运行项目时出现各种各样问题,网上解决方案众说纷纭,模棱两可,这篇文章将带领你从源码层面剖析@PersistenceContext和@Autowired注入EntityManager的区别。
注:spring是采用注解式配置;为了控制篇幅本系列主要分析JPA和hibernate相关源码,需要配置过程和pom依赖的同学请自行百度。

@PersistenceContext和@Autowired注入EntityManager的区别

首先要知道spring对带有@PersistenceContext的属性或方法的处理是在bean后置处理器PersistenceAnnotationBeanPostProcessor中处理的;对带有@Autowired的属性或方法的处理是在bean后置处理器AutowiredAnnotationBeanPostProcessor中处理的。先看这两个BeanPostProcessor是在何处注册到spring的。首先看下容器的构建

 public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
        DemoService bean = context.getBean(DemoService.class);
        bean.customQuery();
}

核心方法为AnnotationConfigApplicationContext构造中的new AnnotatedBeanDefinitionReader()中的AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);方法

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }

            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
        RootBeanDefinition def;
        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
            def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
        }
			// 注册AutowiredAnnotationBeanPostProcessor后置处理器
        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
            def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
        }

        if (jsr250Present && !registry.containsBeanDefinition("org.springframework.context.annotation.internalCommonAnnotationProcessor")) {
            def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalCommonAnnotationProcessor"));
        }
		// 注册PersistenceAnnotationBeanPostProcessor后置处理器
        if (jpaPresent && !registry.containsBeanDefinition("org.springframework.context.annotation.internalPersistenceAnnotationProcessor")) {
            def = new RootBeanDefinition();

            try {
                def.setBeanClass(ClassUtils.forName("org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor", AnnotationConfigUtils.class.getClassLoader()));
            } catch (ClassNotFoundException var6) {
                throw new IllegalStateException("Cannot load optional framework class: org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor", var6);
            }

            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalPersistenceAnnotationProcessor"));
        }

        if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerProcessor")) {
            def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerProcessor"));
        }

        if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerFactory")) {
            def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerFactory"));
        }

        return beanDefs;
    }

上述代码描述了在AnnotationConfigApplicationContext初始化时默认的bean后置处理器的注入。接下来看下PersistenceAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor究竟干了什么注入的EntityManager有何不同。(具体在源码何处被调用就不讲了,不熟悉的可以百度springbean初始化源码)

一、 AutowiredAnnotationBeanPostProcessor

所谓的bean后置处理器就是在spring创建完bean后调用进行后置处理,AutowiredAnnotationBeanPostProcessor的后置处理显而易见就是为bean中带有@Autowired和@Value注解的属性和方法进行DI依赖注入。

主要实现逻辑在postProcessProperties()方法中

@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // a.获取注入元数据(里面包含所以带@Autowired和@Value的方法和属性)
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
      // b.执行元数据的依赖注入
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

步骤a、获取注入元数据findAutowiringMetadata()

private InjectionMetadata findAutowiringMetadata(String beanName, 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.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
          // 上面主要是缓存中获取注入元数据,此处为第一次获取
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

buildAutowiringMetadata();

这里关注一点,如果一个类继承于一个父类或者抽象类,不必通过构造向父类属性传参,可以直接在父类属性上添加@Autowired和@Value,在spring初始化子类时会为父类属性进行依赖注入

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    // 一个校验,判断是否.java开头,无需关注
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			// 获取全部getDeclaredFields,循环执行下面逻辑
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
        // 判断当前属性上是否有@Autowired和@Value
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					boolean required = determineRequiredStatus(ann);
          // 记录属性是否可以注入,即是否带有@Autowired和@Value
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});
			
      // 获取全部getDeclaredMethods,执行下面逻辑
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
        // 判断方法上是否有@Autowired和@Value
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
          // 记录方法是否可以注入,即是否带有@Autowired和@Value
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});
			// 这里细节将父类的属性方法放到前面,优先注入
			elements.addAll(0, currElements);
      // 获取父类,再次循环判断其属性和方法
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
		// 构造注入元数据,传入标记了是否带有@Autowired和@Value的属性和方法集合
		return InjectionMetadata.forElements(elements, clazz);
	}

步骤b、执行元数据的依赖注入InjectionMetadata的inject()方法

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	// 	checkedElements就是InjectionMetadata.forElements(elements, clazz)的elements即上面收集的全部属性和方法
  Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
        // 循环遍历处理没个element
				element.inject(target, beanName, pvs);
			}
		}
	}

如果这个element是方法的话调用的是AutowiredMethodElement的inject()方法

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			if (checkPropertySkipping(pvs)) {
				return;
			}
			Method method = (Method) this.member;
			Object[] arguments;
  		// 是否缓存,第一次访问为false
			if (this.cached) {
				try {
					arguments = resolveCachedArguments(beanName);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					arguments = resolveMethodArguments(method, bean, beanName);
				}
			}
			else {
        // 获取参数
				arguments = resolveMethodArguments(method, bean, beanName);
			}
			if (arguments != null) {
				try {
          // 取消java语言检查限制,因为方法可能为private的
					ReflectionUtils.makeAccessible(method);
          // 调用set方法进行DI依赖注入
					method.invoke(bean, arguments);
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

如果这个element是属性的话调用的是AutowiredFieldElement的inject()方法

@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
      // 是否缓存,第一次访问为false
			if (this.cached) {
				try {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					value = resolveFieldValue(field, bean, beanName);
				}
			}
			else {
        // 获取属性要注入的值,后续调用与AutowiredMethodElement.resolveMethodArguments()相同,后续只讲一种
				value = resolveFieldValue(field, bean, beanName);
			}
			if (value != null) {
        // 取消java语言检查限制,因为属性可能为private的
				ReflectionUtils.makeAccessible(field);
        // 对属性进行赋值
				field.set(bean, value);
			}
		}

resolveFieldValue()

private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			Object value;
			try {
        // 从工厂中获取获取依赖属性值,如果是@Autowired就从工厂里取如果是@Value就从properties中取,
        // 关键点是从spring的bean工厂中获取的单例对象。
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
  		// 设置缓存
			synchronized (this) {
				if (!this.cached) {
					Object cachedFieldValue = null;
					if (value != null || this.required) {
						cachedFieldValue = desc;
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
								cachedFieldValue = new ShortcutDependencyDescriptor(
										desc, autowiredBeanName, field.getType());
							}
						}
					}
					this.cachedFieldValue = cachedFieldValue;
					this.cached = true;
				}
			}
			return value;
		}
	}

DefaultListableBeanFactory.resolveDependency()方法

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
        // 核心方法
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

DefaultListableBeanFactory.doResolveDependency()方法,这里是核心方法

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			Class<?> type = descriptor.getDependencyType();
      // 处理@Value注解,细节处理方法是QualifierAnnotationAutowireCandidateResolver.getSuggestedValue()方法
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				try {
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				}
				catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return (descriptor.getField() != null ?
							converter.convertIfNecessary(value, type, descriptor.getField()) :
							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
				}
			}

			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			// 处理@Autowired注解,根据类型获取bean,可能是多个。
      // key为beanId,如果当前属性在此bean之前被初始化完毕则value为单例工厂singletonObjects中已经初始化完成的单例对象
      // 如果此当前属性此时还未别初始化完成则value为此属性Class类型对象
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {
        // 如果根据类型查找到多个则根据该属性在当前bean中声明的名称或@Qualifier注解设置的名称进行筛选过滤
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
            // 如果未找到匹配的beanName则抛出异常NoUniqueBeanDefinitionException;
            // ...expected single matching bean but found 2...
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
        // 如果是Class说明当前属性尚未被初始化,此处方法最终调用beanFactory.getBean(beanName);方法对改属性进行初始化
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

获取到value值后如果是属性则调用field.set()方法如果是方法则调用method.invoke()方法,至此AutowiredAnnotationBeanPostProcessor后置处理器的工作为bean中带有@Autowired和@Value注解的属性和方法进行DI依赖注入全部完成。

由上面源码分析可知@Autowired注入的EntityManager是从spring bean Factory中获取的(分析了个寂寞,这个结论大伙都知道~),那问题来了spring bean Factory中有多少EntityManager类型的实例呢?又分别是什么时候注入的呢?

先说结论一般有两种:

1、由@EnableJpaRepositories注解注入的beanName=org.springframework.orm.jpa.SharedEntityManagerCreator#0

Spring中有很多Enable开头的注解,其作用大都是借助@Import来收集并注册特定场景相关的bean,可以看到@Import了JpaRepositoriesRegistrar,这个类的主要作用就是想容器中注册特定的BeanDefinition(BeanDefinition不懂的需要科普下spring bean初始化源码或者看SpringDataJPA+Hibernate框架源码剖析(三)框架整合 之 Repository接口实现的生成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3tqpoMFX-1645452033410)(/Users/yangxiaofei/临时/image-20220130140616763.png)]

看父类其父类RepositoryBeanDefinitionRegistrarSupport的registerBeanDefinitions方法,这个方法在spring工厂初始化过程中会调用。

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry, BeanNameGenerator generator) {
        Assert.notNull(metadata, "AnnotationMetadata must not be null!");
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
        Assert.notNull(this.resourceLoader, "ResourceLoader must not be null!");
        if (metadata.getAnnotationAttributes(this.getAnnotation().getName()) != null) {
            AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(metadata, this.getAnnotation(), this.resourceLoader, this.environment, registry, generator);
            RepositoryConfigurationExtension extension = this.getExtension();
            RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource);
            RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource, this.resourceLoader, this.environment);
          // 核心
            delegate.registerRepositoriesIn(registry, extension);
        }
    }

看RepositoryConfigurationDelegate.registerRepositoriesIn()方法,下面源码只是为了证实上面的结论,不分析细节。

 public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension) {
        if (logger.isInfoEnabled()) {
            logger.info(LogMessage.format("Bootstrapping Spring Data %s repositories in %s mode.", extension.getModuleName(), this.configurationSource.getBootstrapMode().name()));
        }
				// 关注方法
        extension.registerBeansForRoot(registry, this.configurationSource);
        RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, this.configurationSource, this.resourceLoader, this.environment);
        List<BeanComponentDefinition> definitions = new ArrayList();
        StopWatch watch = new StopWatch();
        if (logger.isDebugEnabled()) {
            logger.debug(LogMessage.format("Scanning for %s repositories in packages %s.", extension.getModuleName(), this.configurationSource.getBasePackages().stream().collect(Collectors.joining(", "))));
        }

        ApplicationStartup startup = getStartup(registry);
        StartupStep repoScan = startup.start("spring.data.repository.scanning");
        repoScan.tag("dataModule", extension.getModuleName());
        repoScan.tag("basePackages", () -> {
            return (String)this.configurationSource.getBasePackages().stream().collect(Collectors.joining(", "));
        });
        watch.start();
        Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configurations = extension.getRepositoryConfigurations(this.configurationSource, this.resourceLoader, this.inMultiStoreMode);
        Map<String, RepositoryConfiguration<?>> configurationsByRepositoryName = new HashMap(configurations.size());
        Iterator var10 = configurations.iterator();

        while(var10.hasNext()) {
            RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration = (RepositoryConfiguration)var10.next();
            configurationsByRepositoryName.put(configuration.getRepositoryInterface(), configuration);
            BeanDefinitionBuilder definitionBuilder = builder.build(configuration);
            extension.postProcess(definitionBuilder, this.configurationSource);
            if (this.isXml) {
                extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource)this.configurationSource);
            } else {
                extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource)this.configurationSource);
            }

            AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
            beanDefinition.setResourceDescription(configuration.getResourceDescription());
            String beanName = this.configurationSource.generateBeanName(beanDefinition);
            if (logger.isTraceEnabled()) {
                logger.trace(LogMessage.format("Spring Data %s - Registering repository: %s - Interface: %s - Factory: %s", extension.getModuleName(), beanName, configuration.getRepositoryInterface(), configuration.getRepositoryFactoryBeanClassName()));
            }

            beanDefinition.setAttribute("factoryBeanObjectType", configuration.getRepositoryInterface());
            registry.registerBeanDefinition(beanName, beanDefinition);
            definitions.add(new BeanComponentDefinition(beanDefinition, beanName));
        }

        potentiallyLazifyRepositories(configurationsByRepositoryName, registry, this.configurationSource.getBootstrapMode());
        watch.stop();
        repoScan.tag("repository.count", Integer.toString(configurations.size()));
        repoScan.end();
        if (logger.isInfoEnabled()) {
            logger.info(LogMessage.format("Finished Spring Data repository scanning in %s ms. Found %s %s repository interfaces.", watch.getLastTaskTimeMillis(), configurations.size(), extension.getModuleName()));
        }

        return definitions;
    }

再看JpaRepositoryConfigExtension.registerBeansForRoot()方法

public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource config) {
    super.registerBeansForRoot(registry, config);
    Object source = config.getSource();
    // 注意这里注入了一个beanName=emBeanDefinitionRegistrarPostProcessor的bean工厂后置处理器    
  // EntityManagerBeanDefinitionRegistrarPostProcessor(在springbean工厂初始化时候会调用)
    registerLazyIfNotAlreadyRegistered(() -> {
        return new RootBeanDefinition(EntityManagerBeanDefinitionRegistrarPostProcessor.class);
    }, registry, "emBeanDefinitionRegistrarPostProcessor", source);
    registerLazyIfNotAlreadyRegistered(() -> {
        return new RootBeanDefinition(JpaMetamodelMappingContextFactoryBean.class);
    }, registry, "jpaMappingContext", source);
    registerLazyIfNotAlreadyRegistered(() -> {
        return new RootBeanDefinition(PAB_POST_PROCESSOR);
    }, registry, "org.springframework.context.annotation.internalPersistenceAnnotationProcessor", source);
    registerLazyIfNotAlreadyRegistered(() -> {
        RootBeanDefinition contextDefinition = new RootBeanDefinition(DefaultJpaContext.class);
        contextDefinition.setAutowireMode(3);
        return contextDefinition;
    }, registry, "jpaContext", source);
    registerIfNotAlreadyRegistered(() -> {
        return new RootBeanDefinition("org.springframework.data.jpa.util.JpaMetamodelCacheCleanup");
    }, registry, "org.springframework.data.jpa.util.JpaMetamodelCacheCleanup", source);
    registerIfNotAlreadyRegistered(() -> {
        Object value = AnnotationRepositoryConfigurationSource.class.isInstance(config) ? config.getRequiredAttribute("escapeCharacter", Character.class) : config.getAttribute("escapeCharacter").orElse("\\");
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(JpaEvaluationContextExtension.class);
        builder.addConstructorArgValue(value);
        return builder.getBeanDefinition();
    }, registry, JpaEvaluationContextExtension.class.getName(), source);
}

EntityManager相关的注入就在这个beanName=emBeanDefinitionRegistrarPostProcessor的bean工厂后置处理器中完成

看EntityManagerBeanDefinitionRegistrarPostProcessor的postProcessBeanFactory()方法。

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (ConfigurableListableBeanFactory.class.isInstance(beanFactory)) {
            Iterator var3 = BeanDefinitionUtils.getEntityManagerFactoryBeanDefinitions(beanFactory).iterator();

            while(var3.hasNext()) {
                EntityManagerFactoryBeanDefinition definition = (EntityManagerFactoryBeanDefinition)var3.next();
                BeanFactory definitionFactory = definition.getBeanFactory();
                if (definitionFactory instanceof BeanDefinitionRegistry) {
                    BeanDefinitionRegistry definitionRegistry = (BeanDefinitionRegistry)definitionFactory;
                  // 这里完成EntityManager对应beanDefinition的注入,此处相当于xml配置静态工厂注入
                  //<bean name="org.springframework.orm.jpa.SharedEntityManagerCreator#0" class="org.springframework.orm.jpa.SharedEntityManagerCreator" factory-method="createSharedEntityManager"></bean>
                  BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
                    builder.setFactoryMethod("createSharedEntityManager");
                    builder.addConstructorArgReference(definition.getBeanName());
                    AbstractBeanDefinition emBeanDefinition = builder.getRawBeanDefinition();
                    emBeanDefinition.setPrimary(definition.getBeanDefinition().isPrimary());
                    emBeanDefinition.addQualifier(new AutowireCandidateQualifier(Qualifier.class, definition.getBeanName()));
                    emBeanDefinition.setScope(definition.getBeanDefinition().getScope());
                    emBeanDefinition.setSource(definition.getBeanDefinition().getSource());
                    emBeanDefinition.setLazyInit(true);
                    BeanDefinitionReaderUtils.registerWithGeneratedName(emBeanDefinition, definitionRegistry);
                }
            }

        }
    }

看下SharedEntityManagerCreator的createSharedEntityManager方法此处创建的为事务类型的EntityManager

public static EntityManager createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties,
			boolean synchronizedWithTransaction, Class<?>... entityManagerInterfaces) {

		ClassLoader cl = null;
		if (emf instanceof EntityManagerFactoryInfo) {
			cl = ((EntityManagerFactoryInfo) emf).getBeanClassLoader();
		}
		Class<?>[] ifcs = new Class<?>[entityManagerInterfaces.length + 1];
		System.arraycopy(entityManagerInterfaces, 0, ifcs, 0, entityManagerInterfaces.length);
		ifcs[entityManagerInterfaces.length] = EntityManagerProxy.class;
   // 此处使用了JDK的动态代理返回一个事务型的EntityManager代理类,此处InvokeHandler的实现类为SharedEntityManagerInvocationHandler(这个EntityManager调用任何方法都会进SharedEntityManagerInvocationHandler的invoke方法,JDK动态代理原理不懂的自行科普)
		return (EntityManager) Proxy.newProxyInstance(
				(cl != null ? cl : SharedEntityManagerCreator.class.getClassLoader()),
				ifcs, new SharedEntityManagerInvocationHandler(emf, properties, synchronizedWithTransaction));
	}

到此可以看到@EnableJpaRepositories注入的EntityManager为事务型(事务型的特点后面介绍)

2、开发者自己添加@Bean注解注入,大部分网上抄的完全没有必要。

@Bean
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory){
      return  entityManagerFactory.createEntityManager();
    }

上段代码中的EntityManagerFactory是由LocalContainerEntityManagerFactoryBean创建产生的一个代理类,具体创建过程可以看SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建。所以entityManagerFactory.createEntityManager();实际上调用的是ManagedEntityManagerFactoryInvocationHandler.invoke方法,

@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			switch (method.getName()) {
				case "equals":
					// Only consider equal when proxies are identical.
					return (proxy == args[0]);
				case "hashCode":
					// Use hashCode of EntityManagerFactory proxy.
					return System.identityHashCode(proxy);
				case "unwrap":
					// Handle JPA 2.1 unwrap method - could be a proxy match.
					Class<?> targetClass = (Class<?>) args[0];
					if (targetClass == null) {
						return this.entityManagerFactoryBean.getNativeEntityManagerFactory();
					}
					else if (targetClass.isInstance(proxy)) {
						return proxy;
					}
					break;
			}

			try {
        // 此处的entityManagerFactoryBean就是LocalContainerEntityManagerFactoryBean,此处调用的是
       // LocalContainerEntityManagerFactoryBean的父类AbstractEntityManagerFactoryBean.invokeProxyMethod方法
				return this.entityManagerFactoryBean.invokeProxyMethod(method, args);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}

看AbstractEntityManagerFactoryBean.invokeProxyMethod

Object invokeProxyMethod(Method method, @Nullable Object[] args) throws Throwable {
		if (method.getDeclaringClass().isAssignableFrom(EntityManagerFactoryInfo.class)) {
			return method.invoke(this, args);
		}
		else if (method.getName().equals("createEntityManager") && args != null && args.length > 0 &&
				args[0] == SynchronizationType.SYNCHRONIZED) {
			// JPA 2.1's createEntityManager(SynchronizationType, Map)
			// Redirect to plain createEntityManager and add synchronization semantics through Spring proxy
      // 此处调用的是具体JPA实现厂商的会话生成方法,这里是Hibernate的NativeEntityManagerFactory=SessionFactoryImpl,生成的EntityManager=Session
			EntityManager rawEntityManager = (args.length > 1 ?
					getNativeEntityManagerFactory().createEntityManager((Map<?, ?>) args[1]) :
					getNativeEntityManagerFactory().createEntityManager());
			postProcessEntityManager(rawEntityManager);
      // 此处对上面的EntityManager进行扩展型代理封装
			return ExtendedEntityManagerCreator.createApplicationManagedEntityManager(rawEntityManager, this, true);
		}

ExtendedEntityManagerCreator.createApplicationManagedEntityManager()最终调用ExtendedEntityManagerCreator.createProxy()方法

private static EntityManager createProxy(
			EntityManager rawEm, @Nullable Class<? extends EntityManager> emIfc, @Nullable ClassLoader cl,
			@Nullable PersistenceExceptionTranslator exceptionTranslator, @Nullable Boolean jta,
			boolean containerManaged, boolean synchronizedWithTransaction) {

		Assert.notNull(rawEm, "EntityManager must not be null");
		Class<?>[] interfaces;

		if (emIfc != null) {
			interfaces = cachedEntityManagerInterfaces.computeIfAbsent(emIfc, key -> {
				if (EntityManagerProxy.class.equals(key)) {
					return new Class<?>[] {key};
				}
				return new Class<?>[] {key, EntityManagerProxy.class};
			});
		}
		else {
			interfaces = cachedEntityManagerInterfaces.computeIfAbsent(rawEm.getClass(), key -> {
				Set<Class<?>> ifcs = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(key, cl));
				ifcs.add(EntityManagerProxy.class);
				return ClassUtils.toClassArray(ifcs);
			});
		}
	//  // 此处使用了JDK的动态代理返回一个事务型的EntityManager代理类,此处InvokeHandler的实现类为ExtendedEntityManagerInvocationHandler
		return (EntityManager) Proxy.newProxyInstance(
				(cl != null ? cl : ExtendedEntityManagerCreator.class.getClassLoader()),
				interfaces,
				new ExtendedEntityManagerInvocationHandler(
						rawEm, exceptionTranslator, jta, containerManaged, synchronizedWithTransaction));
	}

到此可以看到开发者通过@Bean注入的EntityManager为扩展型(扩展型的特点后面介绍)

3、 @Autowired注入总结

由上面分析可知@Autowired注入EntityManager共分为一下几种情况

  1. 开发者未使用@Bean注册EntityManager时,@Autowired注入EntityManager为事务型

  2. 开发者使用@Bean注册EntityManager时且@Autowired注入属性名称与@Bean标记方法名一致时,此时@Autowired注入EntityManager为扩展型

    @Bean
        public EntityManager entityManager(EntityManagerFactory entityManagerFactory){
          return  entityManagerFactory.createEntityManager();
        }
    -----------------------------------
      @Autowired
      private EntityManager entityManager;
    
  3. 开发者使用@Bean注册EntityManager时且@Autowired注入属性名称与@Bean标记方法名不一致时,此时@Autowired注入EntityManager报错 Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘javax.persistence.EntityManager’ available: expected single matching bean but found 2: entityManager,org.springframework.orm.jpa.SharedEntityManagerCreator#0 因为@Autowired为根据类型注入,而容器中EntityManager类型有两个,而且属性名称与两个beanName都对不上,又没有@Qualifier指定名称所以产生上述错误。

    @Bean
        public EntityManager getEntityManager(EntityManagerFactory entityManagerFactory){
          return  entityManagerFactory.createEntityManager();
        }
    -----------------------------------
      @Autowired
      private EntityManager entityManager;
    

二、 PersistenceAnnotationBeanPostProcessor

由上面的分析可知AutowiredAnnotationBeanPostProcessor处理的@Autowried注解注入的EntityMananger为springbean工厂中的单例EntityManager即下面这段代码的返回值。

 		@Bean
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory){
      return  entityManagerFactory.createEntityManager();
    }

PersistenceAnnotationBeanPostProcessor后置处理器是用来为标注了@PersistenceContext的属性和方法进行DI依赖注入的,接下来看下他注入的EntityManager有何不同,同样从postProcessProperties()方法开始,前几步与AutowiredAnnotationBeanPostProcessor一样。

@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // a.获取注入元数据(里面包含所以带@PersistenceContext和@PersistenceUnit的方法和属性)
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
      // b.执行元数据的依赖注入
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

首先看步骤a.获取注入元数据findAutowiringMetadata()

private InjectionMetadata findAutowiringMetadata(String beanName, 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.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
          // 上面主要是缓存中获取注入元数据,此处为第一次获取
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

buildAutowiringMetadata();

从这里开始与AutowiredAnnotationBeanPostProcessor有所不同

由下段源码可知:1.如果一个类的父类想要注入EntityManager无需通过构造传入,可以直接在父类属性上添加@PersistenceContext注解在spring初始化当前类是会由PersistenceAnnotationBeanPostProcessor为其父类注入EntityManager;2.标记@PersistenceContext的属性和方法不能是static的,且方法只能有一个参数,参数类型为EntityManager的上级类

private InjectionMetadata buildPersistenceMetadata(Class<?> clazz) {
  	// 一个校验,判断是否.java开头,无需关注
		if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(PersistenceContext.class, PersistenceUnit.class))) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			// 获取全部getDeclaredFields,循环执行下面逻辑
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
        // 判断属性上是否有@PersistenceContext和@PersistenceUnit注解
				if (field.isAnnotationPresent(PersistenceContext.class) ||
						field.isAnnotationPresent(PersistenceUnit.class)) {
					if (Modifier.isStatic(field.getModifiers())) {
						// 如果该属性是static静态属性则抛出异常
            throw new IllegalStateException("Persistence annotations are not supported on static fields");
					}
          // 记录属性是否可以注入,即是否带有@PersistenceContext和@PersistenceUnit注解
					currElements.add(new PersistenceElement(field, field, null));
				}
			});
			// 获取全部getDeclaredFields,循环执行下面逻辑
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
        //  判断方法上是否有@PersistenceContext和@PersistenceUnit注解
				if ((bridgedMethod.isAnnotationPresent(PersistenceContext.class) ||
						bridgedMethod.isAnnotationPresent(PersistenceUnit.class)) &&
						method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) {
            // 如果该方法是static静态属性则抛出异常
						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);
					// 记录方法是否可以注入,即是否带有@PersistenceContext和@PersistenceUnit注解
          currElements.add(new PersistenceElement(method, bridgedMethod, pd));
				}
			});
			// 将父类的属性排到前面
			elements.addAll(0, currElements);
      // 获取其父类,继续循环处理父类的属性和方法
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
		// 构造注入元数据,传入标记了是否带有@PersistenceContext和@PersistenceUnit注解的属性和方法集合
		return InjectionMetadata.forElements(elements, clazz);
	}

这里再看下记录每个属性和方法是否带有@PersistenceContext和@PersistenceUnit的元数据元素PersistenceElement的构造方法

public PersistenceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
			super(member, pd);
	// 获取该属性或方法上的@PersistenceContext注解		
  PersistenceContext pc = ae.getAnnotation(PersistenceContext.class);
	// 获取该属性或方法上的@PersistenceUnit注解		
  PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class);
			Class<?> resourceType = EntityManager.class;
			if (pc != null) {
				if (pu != null) {
					// 如果这个属性或方法上同时标注@PersistenceContext和@PersistenceUnit则会抛出异常
          throw new IllegalStateException("Member may only be annotated with either " +
							"@PersistenceContext or @PersistenceUnit, not both: " + member);
				}
				Properties properties = null;
        // 获取@PersistenceContext注解的属性
				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只有在@PersistenceContext注解时不为空,且默认值是PersistenceContextType.TRANSACTION
				this.type = pc.type();
				this.synchronizedWithTransaction = SynchronizationType.SYNCHRONIZED.equals(pc.synchronization());
				this.properties = properties;
			}
			else {
        // 获取@PersistenceUnit的属性
				resourceType = EntityManagerFactory.class;
				this.unitName = pu.unitName();
			}
  		// 检查资源类型,对比属性或方法参数的类型是否为EntityManagerFactory、EntityManager本身或父接口用的isAssignableFrom方法判断,如果不是则抛出异常
			checkResourceType(resourceType);
		}

然后看步骤b.执行元数据的依赖注入InjectionMetadata的inject()方法

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	// 	checkedElements就是InjectionMetadata.forElements(elements, clazz)的elements即上面收集的全部属性和方法
  Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
        // 循环遍历处理没个element
				element.inject(target, beanName, pvs);
			}
		}
	}

此处的InjectedElement的实例都是PersistenceElement,但调用的inject()方法为父类InjectedElement的

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
            if (this.isField) {
                Field field = (Field)this.member;
                // 如果是属性则取消java语言检查,因为可能是private属性
                ReflectionUtils.makeAccessible(field);
                // 为属性进行赋值
                field.set(target, this.getResourceToInject(target, requestingBeanName));
            } else {
                if (this.checkPropertySkipping(pvs)) {
                    return;
                }

                try {
                    
                    Method method = (Method)this.member;
                  // 如果是方法则取消java语言检查,因为可能是private方法
                    ReflectionUtils.makeAccessible(method);
                  // 方法调用invoke进行赋值
                    method.invoke(target, this.getResourceToInject(target, requestingBeanName));
                } catch (InvocationTargetException var5) {
                    throw var5.getTargetException();
                }
            }

        }

此处关键是this.getResourceToInject()方法获取要注入的值,此处调用的是PersistenceElement重写的getResourceToInject()方法

@Override
		protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
			// Resolves to EntityManagerFactory or EntityManager.
			if (this.type != null) {
        // 从步骤a中讲解的PersistenceElement构造可知type当前注解是@PersistenceContext时不为空,所以下面获取的是EntityManager,且type的默认值为PersistenceContextType.TRANSACTION
				return (this.type == PersistenceContextType.EXTENDED ?
            // 此处获取的PersistenceContextType.EXTENDED类型对应扩展型EntityManager;PersistenceContextType.TRANSACTION对应事务型EntityManager
             
						resolveExtendedEntityManager(target, requestingBeanName) :
          
						resolveEntityManager(requestingBeanName));
			}
			else {
				// OK, so we need an EntityManagerFactory...
        // 此处是获取EntityManagerFactory
        // 此处为从spring容器中获取EntityManagerFactory代理对象,后续关键方法调用了PersistenceElement.findEntityManagerFactory(this.unitName, requestingBeanName)方法,此方法在下面resolveExtendedEntityManager或resolveEntityManager方法的解析中会讲到
				return resolveEntityManagerFactory(requestingBeanName);
			}
		}

至此可以发现@PersistenceContext注解即可注入扩展型EntityManager也可注入事务型EntityManager,取决于@PersistenceContext(type=?)。这里最终构建出来的扩展型和事务型与**@Autowired注入篇**构造的完全相同。包括最终调用的核心方法也相同,只是最终方法调用的入参获取逻辑不同,下面着重讲一下@PersistenceContext对扩展型和事务型EntityManager的构建过程。

2.1、 事务型构建

private EntityManager resolveEntityManager(@Nullable String requestingBeanName) {
			// Obtain EntityManager reference from JNDI?
 			// 因为PersistenceAnnotationBeanPostProcessor没有特殊配置,此处获取为null,内部逻辑判断
      // PersistenceAnnotationBeanPostProcessor属性persistenceContexts是否为null,如果为null则返回null
			EntityManager em = getPersistenceContext(this.unitName, false);
			if (em == null) {
				// No pre-built EntityManager found -> build one based on factory.
				// Obtain EntityManagerFactory from JNDI?
        // 此处也为null
				EntityManagerFactory emf = getPersistenceUnit(this.unitName);
				if (emf == null) {
					// Need to search for EntityManagerFactory beans.
          // 这个方法里面逻辑比较简单都是springIOC简单操作就贴后续了。
          // 此处如果unitName=null则根据类型从spring容器中获取EntityManagerFactory,如果存在多个却未指定unitName则会报错;
          // 如果unitName不为空则根据beanName从spring容器中获取EntityManagerFactory;
          
          //注:此处之所以需要第二个参数requestingBeanName即引用EntityManager的beanName,是spring会为DataSource、SqlSession、EntityManager、EntityManagerFactory等这种特殊的类维护的一个依赖关系;比如demoRepositoryImpl引用EntityManager如果spring为这两个类维护了依赖关系,则在EntityManager销毁时会同步销毁demoRepositoryImpl,spring认为如果demoRepositoryImpl没有了EntityManager属性则失去了意义也要销毁。
          
					emf = findEntityManagerFactory(this.unitName, requestingBeanName);
				}
				// Inject a shared transactional EntityManager proxy.
        // 具体情况可以看***SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建***
        // 这个判断比较关键由于spring容器中EntityManagerFactory是个代理类,其实现的接口有EntityManagerFactoryInfo.class、EntityManagerFactory.class、还有具体ORM厂商定义的接口(如hibernate的SessionFactory.class,在HibernateJpaVendorAdapter中定义,其中也储存了EntityManagerInterface为Session.class)。
        //  如果此处为true则下面生成的EntityManager代理对象会实现具体ORM厂商的会话API接口即Session.class;如果为false则生成的EntityManager代理对象会实现要注入属性或者方法参数类型的接口即getResourceType()的结果,如果这样的话代理EntityManager就不具备Hibernate厂商会话API的功能了,是不对的。
				if (emf instanceof EntityManagerFactoryInfo &&
						((EntityManagerFactoryInfo) emf).getEntityManagerInterface() != null) {
					// 生成代理EntityManager
					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;
		}

这里核心方法为SharedEntityManagerCreator.createSharedEntityManager();

public static EntityManager createSharedEntityManager(
			EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction) {
		// 获取代理EntityManager要实现的具体ORM厂商的会话API接口,此处是Session.class
		Class<?> emIfc = (emf instanceof EntityManagerFactoryInfo ?
				((EntityManagerFactoryInfo) emf).getEntityManagerInterface() : EntityManager.class);
   // 调用重载方法
		return createSharedEntityManager(emf, properties, synchronizedWithTransaction,
				(emIfc == null ? NO_ENTITY_MANAGER_INTERFACES : new Class<?>[] {emIfc}));
	}

看下重载方法SharedEntityManagerCreator.createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties,boolean synchronizedWithTransaction, Class<?>… entityManagerInterfaces)

public static EntityManager createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties,
			boolean synchronizedWithTransaction, Class<?>... entityManagerInterfaces) {
		ClassLoader cl = null;
		if (emf instanceof EntityManagerFactoryInfo) {
			cl = ((EntityManagerFactoryInfo) emf).getBeanClassLoader();
		}
  	// 合并代理EntityManager要实现的接口数组目前是Session.class和EntityManagerProxy.class
		Class<?>[] ifcs = new Class<?>[entityManagerInterfaces.length + 1];
		System.arraycopy(entityManagerInterfaces, 0, ifcs, 0, entityManagerInterfaces.length);
		ifcs[entityManagerInterfaces.length] = EntityManagerProxy.class;
    // 使用JDK动态代理创建代理EntityManager对象
		return (EntityManager) Proxy.newProxyInstance(
				(cl != null ? cl : SharedEntityManagerCreator.class.getClassLoader()),
				ifcs, new SharedEntityManagerInvocationHandler(emf, properties, synchronizedWithTransaction));
	}

到此事务类型的EntityManager的构建过程已经分析完毕,最后通过@PersistenceContext注入的是一个实现了Session.class和EntityManagerProxy.class接口的JDK动态代理类,其InvokeHandler的实现类为SharedEntityManagerInvocationHandler(这个EntityManager调用任何方法都会进SharedEntityManagerInvocationHandler的invoke方法,JDK动态代理原理不懂的自行科普)

2.2、扩展型构建

private EntityManager resolveExtendedEntityManager(Object target, @Nullable String requestingBeanName) {
			// 返回null。解释同上事务型
			EntityManager em = getPersistenceContext(this.unitName, true);
			if (em == null) {
				// 返回null。解释同上事务型
				EntityManagerFactory emf = getPersistenceUnit(this.unitName);
				if (emf == null) {
					// 在spring bean Factory中获取EntityManagerFactory,解释同上事务型
					emf = findEntityManagerFactory(this.unitName, requestingBeanName);
				}
				// 创建扩展型EntityManager
				em = ExtendedEntityManagerCreator.createContainerManagedEntityManager(
						emf, this.properties, this.synchronizedWithTransaction);
			}
  			// spring维护一个级联销毁关系,target销毁前也会销毁target中此@PersistenceContext注入的EntityManager
			if (em instanceof EntityManagerProxy && beanFactory != null && requestingBeanName != null &&
					beanFactory.containsBean(requestingBeanName) && !beanFactory.isPrototype(requestingBeanName)) {
				extendedEntityManagersToClose.put(target, ((EntityManagerProxy) em).getTargetEntityManager());
			}
			return em;
		}
	}

ExtendedEntityManagerCreator.createContainerManagedEntityManager();

public static EntityManager createContainerManagedEntityManager(
			EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction) {

		Assert.notNull(emf, "EntityManagerFactory must not be null");
		if (emf instanceof EntityManagerFactoryInfo) {
      // 正常使用LocalContainerEntityManagerFactoryBean构造的EntityManagerFactory代理对象都实现类EntityManagerFactoryInfo接口
			EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
      // 创建具体JPA实现厂商的EntityManager实现此处为Session
			EntityManager rawEntityManager = emfInfo.createNativeEntityManager(properties);
      // 为创建的EntityManager增加代理,添加扩展逻辑支持
			return createProxy(rawEntityManager, emfInfo, true, synchronizedWithTransaction);
		}
		else {
			EntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ?
					emf.createEntityManager(properties) : emf.createEntityManager());
			return createProxy(rawEntityManager, null, null, null, null, true, synchronizedWithTransaction);
		}
	}

createProxy()最终调用重载createProxy()方法

private static EntityManager createProxy(
			EntityManager rawEm, @Nullable Class<? extends EntityManager> emIfc, @Nullable ClassLoader cl,
			@Nullable PersistenceExceptionTranslator exceptionTranslator, @Nullable Boolean jta,
			boolean containerManaged, boolean synchronizedWithTransaction) {

		Assert.notNull(rawEm, "EntityManager must not be null");
		Class<?>[] interfaces;

		if (emIfc != null) {
			interfaces = cachedEntityManagerInterfaces.computeIfAbsent(emIfc, key -> {
				if (EntityManagerProxy.class.equals(key)) {
					return new Class<?>[] {key};
				}
				return new Class<?>[] {key, EntityManagerProxy.class};
			});
		}
		else {
			interfaces = cachedEntityManagerInterfaces.computeIfAbsent(rawEm.getClass(), key -> {
				Set<Class<?>> ifcs = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(key, cl));
				ifcs.add(EntityManagerProxy.class);
				return ClassUtils.toClassArray(ifcs);
			});
		}
		// 使用JDK动态代理创建代理EntityManager对象
		return (EntityManager) Proxy.newProxyInstance(
				(cl != null ? cl : ExtendedEntityManagerCreator.class.getClassLoader()),
				interfaces,
				new ExtendedEntityManagerInvocationHandler(
						rawEm, exceptionTranslator, jta, containerManaged, synchronizedWithTransaction));
	}

到此扩展类型的EntityManager的构建过程已经分析完毕,最后通过@PersistenceContext注入的是一个实现了Session.class和EntityManagerProxy.class接口的JDK动态代理类,其InvokeHandler的实现类为ExtendedEntityManagerInvocationHandler(这个EntityManager调用任何方法都会进SharedEntityManagerInvocationHandler的invoke方法,JDK动态代理原理不懂的自行科普)

2.3、@PersistenceContext注入总结

由上面分析可知@PersistenceContext注入EntityManager共分为一下几种情况

  1. @PersistenceContext或@PersistenceContext(type = PersistenceContextType.TRANSACTION)时注入事务类型EntityManager

     		@PersistenceContext
        private EntityManager entityManager;
    ****************************************************************
        @PersistenceContext(type = PersistenceContextType.TRANSACTION)
        private EntityManager entityManager;
    
  2. @PersistenceContext(type = PersistenceContextType.EXTENDED)时注入扩展型EntityManager

        @PersistenceContext(type = PersistenceContextType.EXTENDED)
        private EntityManager entityManager;
    

三、 扩展EntityManager和事务EntityManager有何不同

通过上述分析得知@Autowired和@PersistenceContext注解注入的EntityManager无非事务型和扩展型两种情况,那事务型和扩展型的区别是什么呢?分别用于什么场景呢?我们日常开发中正确的注入方式是什么?

3.1、事务型执行

事务型EntityManager是个JDK动态代理类,此EntityManager调用任何方法都会被SharedEntityManagerInvocationHandler的invoke方法拦截。我们首先看下SharedEntityManagerInvocationHandler的构造和关键属性

		private final EntityManagerFactory targetFactory;

		@Nullable
		private final Map<?, ?> properties;

		private final boolean synchronizedWithTransaction;

		@Nullable
		private transient volatile ClassLoader proxyClassLoader;

public SharedEntityManagerInvocationHandler(
				EntityManagerFactory target, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction) {
  		// JDK动态代理构造EntityManager时传入,spring bean factory 中的。
			this.targetFactory = target;
			this.properties = properties;
  		// 默认是true,是否与当前事务同步@PersistenceContext的synchronization属性
			this.synchronizedWithTransaction = synchronizedWithTransaction;
			initProxyClassLoader();
		}

首先模拟一个场景如下,当下面这段代码的saveUser1被调用时。接下来看下事务型EntityManager方法调用的执行过程以及事务型特点的体现。

 		@PersistenceContext(type = PersistenceContextType.TRANSACTION)
    private EntityManager entityManager;
		// 注入的是事务型的情况下
    @Autowired
    private EntityManager entityManager1;


    @PostConstruct
    public void init(){
        System.out.println("初始化完成");
    }
		
		// Userid=yxf
   @Transactional
    public void saveUser1(User user){
1      entityManager.merge(user);
       user.setName("修改");
       saveUser2();
   }

    @Transactional
   public void saveUser2(){
        User user = entityManager1.find(User.class, "yxf");
        // 如果entityManager和entityManager1不共用一个Connection根据MySql的默认隔离级别”读已提交“,此处应该是查询不到的。
        if(user!=null){
           	 user.setName("修改");
2            entityManager1.merge(user);
        }
    }

首先当代码1entityManager.merge(user);被调用时进入SharedEntityManagerInvocationHandler.invoke()方法

@Override
		@Nullable
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			// Invocation on EntityManager interface coming in...

			switch (method.getName()) {
				case "equals":
					return (proxy == args[0]);
				case "hashCode":
					return hashCode();
				case "toString":
					return "Shared EntityManager proxy for target factory [" + this.targetFactory + "]";
				case "getEntityManagerFactory":
					return this.targetFactory;
				case "getCriteriaBuilder":
				case "getMetamodel":
					try {
            // CriteriaBuilder和Metamodel其实都是利用EntityManagerFactory生成的并不是Session的内部对象
						return EntityManagerFactory.class.getMethod(method.getName()).invoke(this.targetFactory);
					}
					catch (InvocationTargetException ex) {
						throw ex.getTargetException();
					}
				case "unwrap":
					Class<?> targetClass = (Class<?>) args[0];
					if (targetClass != null && targetClass.isInstance(proxy)) {
						return proxy;
					}
					break;
				case "isOpen":
					return true;
				case "close":
					return null;
				case "getTransaction":
					throw new IllegalStateException(
							"Not allowed to create transaction on shared EntityManager - " +
							"use Spring transactions or EJB CMT instead");
			}
			// 在当前事务中获取EntityManager,此处需要对spring的声明式事务源码有一定基础
			EntityManager target = EntityManagerFactoryUtils.doGetTransactionalEntityManager(
					this.targetFactory, this.properties, this.synchronizedWithTransaction);

			switch (method.getName()) {
				case "getTargetEntityManager":
					if (target == null) {
						throw new IllegalStateException("No transactional EntityManager available");
					}
					return target;
				case "unwrap":
					Class<?> targetClass = (Class<?>) args[0];
					if (targetClass == null) {
						return (target != null ? target : proxy);
					}
					if (target == null) {
						throw new IllegalStateException("No transactional EntityManager available");
					}
					break;
			}
			// transactionRequiringMethods的值见SharedEntityManagerCreator的
      // static{
      //	transactionRequiringMethods.add("joinTransaction");
			//	transactionRequiringMethods.add("flush");
			//	transactionRequiringMethods.add("persist");
			//	transactionRequiringMethods.add("merge");
			//	transactionRequiringMethods.add("remove");
			//	transactionRequiringMethods.add("refresh");
    	//			}代码块,所以此处为true
			if (transactionRequiringMethods.contains(method.getName())) {
				// 当在TransactionSynchronizationManager中获取不到EntityManager或当前线程没有活跃事务时抛出异常
        // 如果saveUser1方法上去除@Transactional注解则会出现此异常
				if (target == null || (!TransactionSynchronizationManager.isActualTransactionActive() &&
						!target.getTransaction().isActive())) {
					throw new TransactionRequiredException("No EntityManager with actual transaction available " +
							"for current thread - cannot reliably process '" + method.getName() + "' call");
				}
			}

			// Regular EntityManager operations.
			boolean isNewEm = false;
			if (target == null) {
				logger.debug("Creating new EntityManager for shared EntityManager invocation");
				target = (!CollectionUtils.isEmpty(this.properties) ?
						this.targetFactory.createEntityManager(this.properties) :
						this.targetFactory.createEntityManager());
				isNewEm = true;
			}

			// Invoke method on current EntityManager.
			try {
        // 执行原方法
				Object result = method.invoke(target, args);
				if (result instanceof Query) {
					Query query = (Query) result;
					if (isNewEm) {
						Class<?>[] ifcs = cachedQueryInterfaces.computeIfAbsent(query.getClass(), key ->
								ClassUtils.getAllInterfacesForClass(key, this.proxyClassLoader));
						result = Proxy.newProxyInstance(this.proxyClassLoader, ifcs,
								new DeferredQueryInvocationHandler(query, target));
						isNewEm = false;
					}
					else {
						EntityManagerFactoryUtils.applyTransactionTimeout(query, this.targetFactory);
					}
				}
				return result;
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
			finally {
				if (isNewEm) {
					EntityManagerFactoryUtils.closeEntityManager(target);
				}
			}
		}

看下事务型EntityManager实现的核心方法EntityManagerFactoryUtils.doGetTransactionalEntityManager(),此处需要对spring的声明式事务源码有一定基础,下面会简单说明讲一下关键,如需要了解细节可以参考Spring事务流程源码剖析+传播行为运用案例+心得 以及SpringDataJPA+Hibernate框架源码剖析(四)框架整合 之 事务管理器的构建(包括spring的事务机制)。(spring的声明式事务依赖于@Transactional注解,标注了@Transactional注解的方法在此方法的定义bean初始化时会包装一层代理,在此方法执行时会进入TransactionAspectSupport.invokeWithinTransaction方法,在invokeWithinTransaction方法中会创建一个connection对象保存到TransactionSynchronizationManager的ThreadLocal中,在后续方法中如果用到数据库操作则直接取ThreadLocal中的connection对象,这也是spring事务传播行为以及标记回归功能实现的关键)

public static EntityManager doGetTransactionalEntityManager(
			EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction)
			throws PersistenceException {

		Assert.notNull(emf, "No EntityManagerFactory specified");
		// 在TransactionSynchronizationManager中获取EntityManagerHolder,在JpaTransactionManager中会创建并保存到TransactionSynchronizationManager
		EntityManagerHolder emHolder =
				(EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
		if (emHolder != null) {
      // 是否同步当前事务
			if (synchronizedWithTransaction) {
        // 此处为false
				if (!emHolder.isSynchronizedWithTransaction()) {
					if (TransactionSynchronizationManager.isActualTransactionActive()) {
						try {
							emHolder.getEntityManager().joinTransaction();
						}
						catch (TransactionRequiredException ex) {
							logger.debug("Could not join transaction because none was actually active", ex);
						}
					}
					if (TransactionSynchronizationManager.isSynchronizationActive()) {
						Object transactionData = prepareTransaction(emHolder.getEntityManager(), emf);
						TransactionSynchronizationManager.registerSynchronization(
								new TransactionalEntityManagerSynchronization(emHolder, emf, transactionData, false));
						emHolder.setSynchronizedWithTransaction(true);
					}
				}
        // 返回在TransactionSynchronizationManager中获取的EntityManager
				emHolder.requested();
				return emHolder.getEntityManager();
			}
			else {
				// unsynchronized EntityManager demanded
				if (emHolder.isTransactionActive() && !emHolder.isOpen()) {
					if (!TransactionSynchronizationManager.isSynchronizationActive()) {
						return null;
					}
					// EntityManagerHolder with an active transaction coming from JpaTransactionManager,
					// with no synchronized EntityManager having been requested by application code before.
					// Unbind in order to register a new unsynchronized EntityManager instead.
					TransactionSynchronizationManager.unbindResource(emf);
				}
				else {
					// Either a previously bound unsynchronized EntityManager, or the application
					// has requested a synchronized EntityManager before and therefore upgraded
					// this transaction's EntityManager to synchronized before.
					return emHolder.getEntityManager();
				}
			}
		}
		else if (!TransactionSynchronizationManager.isSynchronizationActive()) {
			// 当前方法未标注@Transactional注解时TransactionSynchronizationManager没获取到EntityManager,返回null
			return null;
		}
 
**********如果事务管理器没有使用JapTransactionManager会用到下面代码,正常配置下面代码用不到****************************
  
		// Create a new EntityManager for use within the current transaction.
		logger.debug("Opening JPA EntityManager");
		EntityManager em = null;
		if (!synchronizedWithTransaction) {
			try {
				em = emf.createEntityManager(SynchronizationType.UNSYNCHRONIZED, properties);
			}
			catch (AbstractMethodError err) {
				// JPA 2.1 API available but method not actually implemented in persistence provider:
				// falling back to regular createEntityManager method.
			}
		}
		if (em == null) {
			em = (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager());
		}

		try {
			// Use same EntityManager for further JPA operations within the transaction.
			// Thread-bound object will get removed by synchronization at transaction completion.
			emHolder = new EntityManagerHolder(em);
			if (synchronizedWithTransaction) {
				Object transactionData = prepareTransaction(em, emf);
				TransactionSynchronizationManager.registerSynchronization(
						new TransactionalEntityManagerSynchronization(emHolder, emf, transactionData, true));
				emHolder.setSynchronizedWithTransaction(true);
			}
			else {
				// Unsynchronized - just scope it for the transaction, as demanded by the JPA 2.1 spec...
				TransactionSynchronizationManager.registerSynchronization(
						new TransactionScopedEntityManagerSynchronization(emHolder, emf));
			}
			TransactionSynchronizationManager.bindResource(emf, emHolder);
		}
		catch (RuntimeException ex) {
			// Unexpected exception from external delegation call -> close EntityManager and rethrow.
			closeEntityManager(em);
			throw ex;
		}

		return em;
	}

​ 由上述分析可知,事务型EntityManager是个代理类,代理类执行的时候从TransactionSynchronizationManager中获取EntityManager,TransactionSynchronizationManager中的EntityManager第一次由JpaTransactionManager中创建调用的AbstractEntityManagerFactoryBean.createNativeEntityManager方法创建,而connect也在这个时候初始化(LogicalConnectionManagedImpl.getPhysicalConnection方法),并且放入TransactionSynchronizationManager.事务范围的EntityManager必须依赖于@Transactional注解,如果没有的话则TransactionSynchronizationManager没有EntityManager会报错No EntityManager with actual transaction available for current thread - cannot reliably process ‘merge’ call

在上述场景中entityManager1和entityManager在执行时使用的是同一个Session实例和同一个Connection实例进行数据库操作保证持久化上下文一致以及JPA事务的原子性,最终执行结果为

 insert into t_user (age, name, id) values (18, 'yangxiaofei', 'yxf');
 update t_user set name='修改' where id='yxf';

3.2、扩展型执行

事务型EntityManager是个JDK动态代理类,此EntityManager调用任何方法都会被ExtendedEntityManagerInvocationHandler的invoke方法拦截。我们首先看下ExtendedEntityManagerInvocationHandler的构造和关键属性

		private final EntityManager target;
		@Nullable
		private final PersistenceExceptionTranslator exceptionTranslator;

		private final boolean jta;

		private final boolean containerManaged;

		private final boolean synchronizedWithTransaction;

		private ExtendedEntityManagerInvocationHandler(EntityManager target,
				@Nullable PersistenceExceptionTranslator exceptionTranslator, @Nullable Boolean jta,
				boolean containerManaged, boolean synchronizedWithTransaction) {
			// 在JDK动态生成扩展型代理对象时传入,调用EntityManagerFactory.createNativeEntityManager()方法生成,一个@PersistenceContext对应一个固定的target
			this.target = target;
			this.exceptionTranslator = exceptionTranslator;
      // JTA是JDK解决分布式事务的一种方式
			this.jta = (jta != null ? jta : isJtaEntityManager());
			this.containerManaged = containerManaged;
      // 默认是true,是否与当前事务同步@PersistenceContext的synchronization属性
			this.synchronizedWithTransaction = synchronizedWithTransaction;
		}

首先模拟一个场景如下,当下面这段代码的saveUser1被调用时。接下来看下扩展型EntityManager方法调用的执行过程以及扩展型特点的体现。

		@PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;
    
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager1;


    @PostConstruct
    public void init(){
        System.out.println("初始化完成");
    }
		
		// Userid=yxf
   @Transactional
    public void saveUser1(User user){
1      entityManager.merge(user);
       user.setName("修改");
       saveUser2();
   }

    @Transactional
   public void saveUser2(){
        User user = entityManager1.find(User.class, "yxf");
        // 如果entityManager和entityManager1不共用一个Connection根据MySql的默认隔离级别”读已提交“,此处应该是查询不到的。
        if(user!=null){
           	 user.setName("修改");
2            entityManager1.merge(user);
        }
    }

首先当代码1entityManager.merge(user);被调用时进入ExtendedEntityManagerInvocationHandler.invoke()方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			switch (method.getName()) {
				case "equals":
					return (proxy == args[0]);
				case "hashCode":
					return hashCode();
				case "getTargetEntityManager":
					return this.target;
				case "unwrap":
					Class<?> targetClass = (Class<?>) args[0];
					if (targetClass == null) {
						return this.target;
					}
					else if (targetClass.isInstance(proxy)) {
						return proxy;
					}
					break;
				case "isOpen":
					if (this.containerManaged) {
						return true;
					}
					break;
				case "close":
					if (this.containerManaged) {
						throw new IllegalStateException("Invalid usage: Cannot close a container-managed EntityManager");
					}
					ExtendedEntityManagerSynchronization synch = (ExtendedEntityManagerSynchronization)
							TransactionSynchronizationManager.getResource(this.target);
					if (synch != null) {
						synch.closeOnCompletion = true;
						return null;
					}
					break;
				case "getTransaction":
					if (this.synchronizedWithTransaction) {
						throw new IllegalStateException(
								"Cannot obtain local EntityTransaction from a transaction-synchronized EntityManager");
					}
					break;
				case "joinTransaction":
					doJoinTransaction(true);
					return null;
				case "isJoinedToTransaction":
					// Handle JPA 2.1 isJoinedToTransaction method for the non-JTA case.
					if (!this.jta) {
						return TransactionSynchronizationManager.hasResource(this.target);
					}
					break;
			}

			if (this.synchronizedWithTransaction && method.getDeclaringClass().isInterface()) {
        // 加入当前事务
				doJoinTransaction(false);
			}

			try {
        // 执行原方法
				return method.invoke(this.target, args);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}

扩展型EntityManager实现的核心方法为doJoinTransaction(false);

private void doJoinTransaction(boolean enforce) {
			if (this.jta) {
				// Let's try whether we're in a JTA transaction.
				try {
					this.target.joinTransaction();
					logger.debug("Joined JTA transaction");
				}
				catch (TransactionRequiredException ex) {
					if (!enforce) {
						logger.debug("No JTA transaction to join: " + ex);
					}
					else {
						throw ex;
					}
				}
			}
			else {
        // 我们不考虑分布式事务故jta在初始化时设置为false
        // 判断当前线程下是否有已启动事务,其实就是看看当前调用的方法或上层方法有无@Transactional
				if (TransactionSynchronizationManager.isSynchronizationActive()) {
          // 判断当前EntityManager是否已经加入了当前事务
					if (!TransactionSynchronizationManager.hasResource(this.target) &&
							!this.target.getTransaction().isActive()) {
            // 如果为加入则加入到当前事务中
						enlistInCurrentTransaction();
					}
					logger.debug("Joined local transaction");
				}
				else {
					if (!enforce) {
            // 此处enforce为false,代表如果当前线程无事务可以加入,打印日志不抛出异常;
            // 为true代表如果当前线程无事务可以加入则抛出异常
						logger.debug("No local transaction to join");
					}
					else {
						throw new TransactionRequiredException("No local transaction to join");
					}
				}
			}
		}

关键方法enlistInCurrentTransaction();

private void enlistInCurrentTransaction() {
			// 获取当前EntityManager的事务对象
			EntityTransaction et = this.target.getTransaction();
  		// 启动事务
			et.begin();
			if (logger.isDebugEnabled()) {
				logger.debug("Starting resource-local transaction on application-managed " +
						"EntityManager [" + this.target + "]");
			}
  		// 封装事务同步对象
			ExtendedEntityManagerSynchronization extendedEntityManagerSynchronization =
					new ExtendedEntityManagerSynchronization(this.target, this.exceptionTranslator);
  		// 添加到TransactionSynchronizationManager的resources属性,用于上一步的TransactionSynchronizationManager.hasResource(this.target)判断,避免重复注册
			TransactionSynchronizationManager.bindResource(this.target, extendedEntityManagerSynchronization);
  		// 添加到TransactionSynchronizationManager的synchronizations属性,synchronizations是个set集合,在声明式事务的切面TransactionAspectSupport.invokeWithinTransaction方法的最后会遍历synchronizations中的事务同步对象进行commit或rollback。细节参考SpringDataJPA+Hibernate框架源码剖析(四)框架整合 之 事务管理器的构建(包括spring的事务机制)
			TransactionSynchronizationManager.registerSynchronization(extendedEntityManagerSynchronization);
		}

扩展型的EntityManager是个代理类,每个代理类里面都包含一个EntityManager实例,注入的时候调用AbstractEntityManagerFactoryBean.createNativeEntityManager方法创建。在方法执行的时候会先判断当前线程下有没有可以用的事务TransactionSynchronizationManager.isSynchronizationActive()如果有的话则加入当前事务,所谓加入就是将代理类里的EntityManager实例的事务对象保存到TransactionSynchronizationManager的synchronizations属性中,并启动EntityManager的事务,当前事务结束时会有后置处理去commit或者robaclks synchronizations中的事务。说是加入到当前事务但是与当前事务不共用同一个链接,所以不能保证原子性。扩展范围的EntityManager也必须要依赖于@Transactional如果当前线程没有可加入的事务虽然不会报错,但是只能执行查询,无法执行增删改操作,因为事务无法调用Connection的commit方法所以增删改不会生效。

上述场景entityManager和entityManager1在真正执行时使用的是不同的Session实例和不同的Connection实例,在MySql的默认隔离级别”读已提交“下entityManager1.find(User.class, “yxf”);查询不到结果。

 insert into t_user (age, name, id) values (18, 'yangxiaofei', 'yxf');

3.3、扩展型和事务型EntityManager总结

我们日常开发的java项目大都是基于Spring框架的web项目,大多作为服务端需要支持多线程并发访问,所以我们应该选中事务型EntityManager。在配置时主要一下两点:

  • 开发者不要使用@Bean注册EntityManage,否则不要使用@Autowired注入
  • 使用@PersistenceContext注入时type属性为空或者PersistenceContextType.TRANSACTION

下面再通过几个场景证明一下扩展型不适合日常开发的原因:

  1. 如下代码,我们日常使用事务型EntityManager开发时下面这种场景应该是比较常见的,保存一个实体后在同一个事务中是可以查询到的。
@Service
public class AService {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;
    @Autowired
    private BService bService;

    @Transactional
    public void method(){
        User user=new User();
        user.setId("yxf");
        user.setName("yangxiaofei");
        user.setAge(18);
        entityManager.merge(user);
        bService.method(user.getId());
    }
}


@Service
public class BService {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;
  
		@Transactional
    public void method(String id){
        User user = entityManager.find(User.class, "yxf");
        if(user!=null){
            System.out.println("未查询到"+user);
        }else {
            System.out.println("未查询到");
        }
    }
}

上述场景输出结果为

未查询到

原因是AService和BService中的entityManager代理对象在执行时使用的是不同的Session实例(即ExtendedEntityManagerInvocationHandler中的target属性不同),Session中的PersistenceContext持久化上下文和Connection实例也不同所以在事务提交前互相不可见,故BService查询不到AService中尚未提交的事务

  1. 如下代码在日常使用事务型EntityManager开发时,我们期望的结果应该是执行一次insert执行一次update
@Service
public class AService {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;
    @Autowired
    private BService bService;

    @Transactional
    public void method(){
        User user=new User();
        user.setId("yxf");
        user.setName("yangxiaofei");
        user.setAge(18);
        entityManager.merge(user);
        bService.method(user);
    }
}


@Service
public class BService {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;
  
		@Transactional
    public void method(User user){
      	 user.setName("yangxiaofei修改");
         entityManager.merge(user);
    }
}

上述场景输出结果为抛出异常,下面是异常日志

10:14:24.708 [main] DEBUG org.hibernate.SQL - select user0_.id as id1_1_1_, user0_.age as age2_1_1_, user0_.name as name3_1_1_, books1_.userId as userid3_0_3_, books1_.bookId as bookid1_0_3_, books1_.bookId as bookid1_0_0_, books1_.bookName as bookname2_0_0_, books1_.userId as userid3_0_0_ from t_user user0_ left outer join t_book books1_ on user0_.id=books1_.userId where user0_.id=?
10:14:24.798 [main] DEBUG org.hibernate.SQL - select user0_.id as id1_1_1_, user0_.age as age2_1_1_, user0_.name as name3_1_1_, books1_.userId as userid3_0_3_, books1_.bookId as bookid1_0_3_, books1_.bookId as bookid1_0_0_, books1_.bookName as bookname2_0_0_, books1_.userId as userid3_0_0_ from t_user user0_ left outer join t_book books1_ on user0_.id=books1_.userId where user0_.id=?
10:14:24.822 [main] DEBUG org.hibernate.SQL - insert into t_user (age, name, id) values (?, ?, ?)
10:14:24.828 [main] DEBUG org.hibernate.SQL - insert into t_user (age, name, id) values (?, ?, ?)
10:14:24.844 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1062, SQLState: 23000
10:14:24.844 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Duplicate entry 'yxf' for key 't_user.PRIMARY'

上述日志打印的sql执行和我们预想的不一样执行了两次insert,导致第二次inert执行时出现了主键冲突。原因是AService和BService中的EntityManager在执行时使用的Session实例不同,他们在执行merge方法时都会产生一个事务同步对象添加到添加到TransactionSynchronizationManager的synchronizations属性中,上述场景中synchronizations中添加了两个事务同步对象,因为互相不可见所以两个Session分别查询数据库和持久化上下文发现并无主键为‘yxf’的对象,都判定为insert操作等待后续commit,在最外层事务方法AService的method执行完毕后,事务管理器切面中将遍历synchronizations中的事务同步对象进行commit,当第二个commit时发现’yxf’主键库里已经存在则抛出异常,但是此时第一个inert已经成功提交了事务故无法回滚了,所以上述情景下使用扩展型不仅会造成持久化上下文冲突还无法保证声明式事务的原子性。

注:严格说这种情况下事务切面中存在三个Connection对象,因为事务切面本身就会初始化一个Connection只是扩展型没用罢了,这样一个线程占用三个数据库链接资源也是不合理的。

  1. 除以上两种场景外,在同一个Service里多线程场景下也会有问题如下
@Service
public class AService {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;
    @Autowired
    private BService bService;



    @Transactional
    public void method1(){
        System.out.println("执行1");
        User user = entityManager.find(User.class, "yxf");
        user.setAge(user.getAge()+1);
        entityManager.merge(user);
    }

    @Transactional
    public void method2(){
        System.out.println("执行2");
        User user = entityManager.find(User.class, "yxf");
        entityManager.remove(user);
    }

}

线程1在调用method1尚未结束时,线程2调用method2执行完毕,此时当线程1提交事务时就会出现异常

Exception in thread "Thread-1" javax.persistence.PersistenceException: org.hibernate.HibernateException: collection was evicted

原因是扩展型EntityManager在多线程调用下始终使用一个Session实例即ExtendedEntityManagerInvocationHandler中的target属性,并不会从TransactionSynchronizationManager的ThreadLocal相关属性中获取,不能保证线程唯一,所以多线程的情况下会出现共同操作持久化上下文导致的冲突问题,这种问题不可预知。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值