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的区别
    • 一、 AutowiredAnnotationBeanPostProcessor
      • 1、由@EnableJpaRepositories注解注入的beanName=org.springframework.orm.jpa.SharedEntityManagerCreator#0
      • 2、开发者自己添加@Bean注解注入,大部分网上抄的完全没有必要。
      • 3、 @Autowired注入总结
    • 二、 PersistenceAnnotationBeanPostProcessor
      • 2.1、 事务型构建
      • 2.2、扩展型构建
      • 2.3、@PersistenceContext注入总结
    • 三、 扩展EntityManager和事务EntityManager有何不同
      • 3.1、事务型执行
      • 3.2、扩展型执行
      • 3.3、扩展型和事务型EntityManager总结

@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()方法中

@Overridepublic 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和@ValueMergedAnnotation<?> 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和@ValuecurrElements.add(new AutowiredFieldElement(field, required));}});// 获取全部getDeclaredMethods,执行下面逻辑ReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}// 判断方法上是否有@Autowired和@ValueMergedAnnotation<?> 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和@ValuecurrElements.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) {// 循环遍历处理没个elementelement.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;// 是否缓存,第一次访问为falseif (this.cached) {try {arguments = resolveCachedArguments(beanName);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvearguments = 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()方法

@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;// 是否缓存,第一次访问为falseif (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = 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接口实现的生成

看父类其父类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注解注入,大部分网上抄的完全没有必要。

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

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

@Overridepublic 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=SessionEntityManager 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的实现类为ExtendedEntityManagerInvocationHandlerreturn (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为扩展型

    @Beanpublic EntityManager entityManager(EntityManagerFactory entityManagerFactory){return  entityManagerFactory.createEntityManager();}
    -----------------------------------@Autowiredprivate 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指定名称所以产生上述错误。

    @Beanpublic EntityManager getEntityManager(EntityManagerFactory entityManagerFactory){return  entityManagerFactory.createEntityManager();}
    -----------------------------------@Autowiredprivate EntityManager entityManager;
    

二、 PersistenceAnnotationBeanPostProcessor

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

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

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

@Overridepublic 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.TRANSACTIONthis.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) {// 循环遍历处理没个elementelement.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()方法

@Overrideprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {// Resolves to EntityManagerFactory or EntityManager.if (this.type != null) {// 从步骤a中讲解的PersistenceElement构造可知type当前注解是@PersistenceContext时不为空,所以下面获取的是EntityManager,且type的默认值为PersistenceContextType.TRANSACTIONreturn (this.type == PersistenceContextType.EXTENDED ?// 此处获取的PersistenceContextType.EXTENDED类型对应扩展型EntityManager;PersistenceContextType.TRANSACTION对应事务型EntityManagerresolveExtendedEntityManager(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则返回nullEntityManager em = getPersistenceContext(this.unitName, false);if (em == null) {// No pre-built EntityManager found -> build one based on factory.// Obtain EntityManagerFactory from JNDI?// 此处也为nullEntityManagerFactory 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) {// 生成代理EntityManagerem = 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.classClass<?> 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.classClass<?>[] 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);}// 创建扩展型EntityManagerem = ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf, this.properties, this.synchronizedWithTransaction);}// spring维护一个级联销毁关系,target销毁前也会销毁target中此@PersistenceContext注入的EntityManagerif (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实现此处为SessionEntityManager 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

          @PersistenceContextprivate 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;@Nullableprivate final Map<?, ?> properties;private final boolean synchronizedWithTransaction;@Nullableprivate 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;// 注入的是事务型的情况下@Autowiredprivate EntityManager entityManager1;@PostConstructpublic void init(){System.out.println("初始化完成");}// Userid=yxf@Transactionalpublic void saveUser1(User user){
1      entityManager.merge(user);user.setName("修改");saveUser2();}@Transactionalpublic 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@Nullablepublic 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");//            }代码块,所以此处为trueif (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中会创建并保存到TransactionSynchronizationManagerEntityManagerHolder emHolder =(EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);if (emHolder != null) {// 是否同步当前事务if (synchronizedWithTransaction) {// 此处为falseif (!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中获取的EntityManageremHolder.requested();return emHolder.getEntityManager();}else {// unsynchronized EntityManager demandedif (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,返回nullreturn 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;@Nullableprivate 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对应一个固定的targetthis.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;@PostConstructpublic void init(){System.out.println("初始化完成");}// Userid=yxf@Transactionalpublic void saveUser1(User user){
1      entityManager.merge(user);user.setName("修改");saveUser2();}@Transactionalpublic 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// 判断当前线程下是否有已启动事务,其实就是看看当前调用的方法或上层方法有无@Transactionalif (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;@Autowiredprivate BService bService;@Transactionalpublic 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;@Transactionalpublic 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;@Autowiredprivate BService bService;@Transactionalpublic 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;@Transactionalpublic 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;@Autowiredprivate BService bService;@Transactionalpublic void method1(){System.out.println("执行1");User user = entityManager.find(User.class, "yxf");user.setAge(user.getAge()+1);entityManager.merge(user);}@Transactionalpublic 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相关属性中获取,不能保证线程唯一,所以多线程的情况下会出现共同操作持久化上下文导致的冲突问题,这种问题不可预知。

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

  1. 【java集合框架源码剖析系列】java源码剖析之ArrayList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...

  2. 阿里中间件seata源码剖析六:TCC模式中2阶段提交实现

    目录 TM通知TC事务状态 TC通知RM分支事务提交 RM处理TC提交事务请求 总结 上篇文章中,我们以TCC模式的demo为例,讲解了seata中全局事务的开启.在这个demo中,TM作为一个全局事 ...

  3. 【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法

    注:关于排序算法,博主写过[数据结构排序算法系列]数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过 ...

  4. Java集合框架源码剖析:LinkedHashSet 和 LinkedHashMap

    Java LinkedHashMap和HashMap有什么区别和联系?为什么LinkedHashMap会有着更快的迭代速度?LinkedHashSet跟LinkedHashMap有着怎样的内在联系?本 ...

  5. Apache Flink fault tolerance源码剖析(六)

    上篇文章我们分析了基于检查点的用户状态的保存机制--状态终端.这篇文章我们来分析barrier(中文常译为栅栏或者屏障,为了避免引入名称争议,此处仍用英文表示).检查点的barrier是提供exact ...

  6. 集合框架源码分析六之堆结构的实现(PriorityQueue)

    /** * * 优先队列是用了一种叫做堆的高效的数据结构, * 堆是用二叉树来描述的,对任意元素n,索引从0开始,如果有子节点的话,则左子树为 * 2*n+1,右子树为2*(n+1). * 以堆实现的 ...

  7. Mina2.0框架源码剖析(八)

    这篇来看看AbstractPollingIoConnector抽象类,它用于用于实现客户端连接的轮询策略.处理逻辑基本上和上一篇文章说的AbstractPollingIoAcceptor类似,它继承自 ...

  8. 源码 状态机_阿里中间件seata源码剖析七:saga模式实现

    saga模式是分布式事务中使用比较多的一种模式,他主要应用在长流程的服务,对一个全局事务,如果某个节点抛出了异常,则从这个节点往前依次回滚或补偿事务.今天我们就来看看它的源码实现. 状态机初始化 在之 ...

  9. Spring框架AOP源码剖析

    今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西的源码剖析,作为多年的开发者,想必大家在面试的时候都被问过,你知道Spring框架AOP的底层实现机制吗 ...

最新文章

  1. 样式集(一) 通用商品列表样式
  2. SAP事务码f-02做账界面显示“页数”字段
  3. python编程可以做什么工作-Python学到什么程度才可以去找工作?掌握这4点足够了!...
  4. Lucene教程--入门程序详解
  5. php删除文见,php如何删除文件夹
  6. php api json,PHP API接口必备之输出json格式数据实例详解
  7. Zoom 是如何击败科技巨头的?
  8. shell的函数返回值
  9. 黑群晖二合一已损毁_黑群晖DSM6.2硬盘引导二合一镜像以及安装方法
  10. 免费复制百度文库上的内容
  11. steam无法连接至计算机,无法连接至steam网络怎么办 无法连接至steam网络解决方法【图文】...
  12. python os.walk如何不遍历隐藏文件,Python os.walk() 遍历出当前目录下的文件夹和文件...
  13. 华为鸿蒙系统推升级应用名称,华为哪些手机可以用鸿蒙系统?华为手机鸿蒙系统升级名单公布...
  14. python编写一个赛车游戏
  15. android 视频恢复软件,手机视频恢复软件
  16. task_struct结构
  17. 数学与计算机科学奖的是,2018未来科学数学与计算机科学奖揭晓:林本坚获奖
  18. 万能电视遥控器代码表
  19. 操作系统_第二章_UNIX操作系统简介
  20. 洛谷 10月 csp-s 模拟赛 T1,T2解析及代码

热门文章

  1. 【操作系统】多线程、生产者——消费者同步与互斥代码实现
  2. c#程序设计实训报告心得体会_C#程序实际实训总结
  3. java获取百度网页内容
  4. STL之vector函数详解
  5. 详解 P沟道mos管与N沟道mos管
  6. 我对计算机网络技术的理解,对计算机网络技术课程学习几点思考.doc
  7. 100Mhz秒脉冲发生器 vivado
  8. Python学习笔记——照片换底色
  9. 修改MySQL数据库的密码
  10. QQ2012如何恢复“合并会话窗口”为多个聊天窗口?