{"id":222,"date":"2011-11-21T02:36:11","date_gmt":"2011-11-21T01:36:11","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=222"},"modified":"2018-09-14T14:00:25","modified_gmt":"2018-09-14T14:00:25","slug":"spring-persistencecontext-explained","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=222","title":{"rendered":"Spring @PersistenceContext\/@PersistenceUnit explained"},"content":{"rendered":"<p>This is the 2nd article of a serie on Spring code analysis.<\/p>\n<p>Today we are going to dig into the <em>@PersistenceContext<\/em> annotation, widely used by JPA\/Hibernate developers to inject an Entity Manager into their DAO classes.<\/p>\n<p><!--more--><br \/>\nIf you&#8217;ve missed the first article about Spring @Transactional, have a look here: <a href=\"https:\/\/www.doanduyhai.com\/blog\/?p=95\" title=\"Spring @Transactional explained\" target=\"_blank\">Spring @Transactional explained<\/a><\/p>\n<blockquote><p>Note: the following code analysis was done with <strong>Spring 3.0.5<\/strong> official release We only focus on the <strong>J2SE environment (no EJB)<\/strong> and on the <strong>JPA API<\/strong> for database management. However, the code analyzed is generic enough to apply, to some extent, to other cases (J2EE platform, specific vendor JPA API\u2026)<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h1>I Usage &amp; use cases<\/h1>\n<pre class=\"brush: java; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n\r\n@PersistenceContext(unitName = &quot;myPersistenceUnit&quot;)\r\nprivate EntityManager entityManager;\r\n\r\nor \r\n\r\n@PersistenceUnit(unitName = &quot;myPersistenceUnit&quot;)\r\nprivate EntityManagerManager entityManagerManager;\r\n<\/pre>\n<ul>\n<li>USE CASE 1:  <strong>within no @Transactional method<\/strong><\/li>\n<pre class=\"brush: java; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  @PersistenceContext(unitName = &quot;myPersistenceUnit&quot;)\r\n  private EntityManager entityManager;\r\n\r\n  public void querySomething()\r\n  {\r\n\tthis.entityManager.createQuery(\u201csome HQL\u201d);\r\n\t\u2026\r\n  }\r\n<\/pre>\n<li>USE CASE 2: <strong>within simple @Transactional method<\/strong><\/li>\n<pre class=\"brush: java; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  @PersistenceContext(unitName = &quot;myPersistenceUnit&quot;)\r\n  private EntityManager entityManager;\r\n\r\n  @Transactional(value = &quot;myTransactionManager&quot;,propagation = Propagation.REQUIRED)\r\n  public void querySomething()\r\n  {\r\n\tthis.entityManager.createQuery(\u201csome HQL\u201d);\r\n\t\u2026\r\n  }\r\n<\/pre>\n<li>USE CASE 3: <strong>nested @Transactional methods<\/strong><\/li>\n<pre class=\"brush: java; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  @Transactional(value = &quot;myTransactionManager&quot;,propagation = Propagation.REQUIRED)\r\n  public void querySomething()\r\n  {\r\n\tthis.entityManager.createQuery(\u201csome HQL\u201d);\r\n\t\u2026\r\n\tthis.injectedBean.transactionalMethod(parameters);\r\n  }\r\n \r\n  ...\r\n  public class InjectedBean {\r\n\r\n  @PersistenceContext(unitName = &quot;oracleNoCachePersistenceUnit&quot;)\r\n  private EntityManager entityManager;\r\n\r\n  @Transactional(value = &quot;myTransactionManager&quot;,propagation = Propagation.REQUIRED)\r\n  public void transactionalMethod(\u2026parameters)\r\n  {\r\n     this.entityManager.createQuery(\u201csome other HQL\u201d);\r\n  }\r\n<\/pre>\n<\/ul>\n<p>&nbsp;<\/p>\n<h1>II Registration in Spring context<\/h1>\n<pre class=\"brush: xml; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n &lt;context:annotation-config\/&gt;\r\n<\/pre>\n<p>or<\/p>\n<pre class=\"brush: xml; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n &lt;bean class=&quot;org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor&quot; \/&gt;\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>III Code analysis<\/h1>\n<h2>A Bean registration<\/h2>\n<p>&nbsp;<\/p>\n<h5>\n1) org.springframework.context.annotation.<strong>ComponentScanBeanDefinitionParser<\/strong><br \/>\n<\/h5>\n<pre class=\"brush: java; highlight: [16,21,22]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\nprivate static final String ANNOTATION_CONFIG_ATTRIBUTE = &quot;annotation-config&quot;;\r\n...\r\nprotected void registerComponents(XmlReaderContext readerContext, Set&lt;BeanDefinitionHolder&gt; beanDefinitions, Element element) {\r\n\r\n\tObject source = readerContext.extractSource(element);\r\n\tCompositeComponentDefinition compositeDef = new \r\n                           CompositeComponentDefinition(element.getTagName(), source);\r\n\r\n\tfor (BeanDefinitionHolder beanDefHolder : beanDefinitions) {\r\n\t\tcompositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));\r\n\t}\r\n\r\n\t\/\/ Register annotation config processors, if necessary.\r\n\tboolean annotationConfig = true;\r\n\tif (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {\r\n\t\tannotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));\r\n\t}\r\n\tif (annotationConfig) {\r\n\t\tSet&lt;BeanDefinitionHolder&gt; processorDefinitions =\r\n                \/\/ (see Point A)\r\n\t\tAnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(),\r\n                 source);\r\n\t        \r\n                for (BeanDefinitionHolder processorDefinition : processorDefinitions) {\r\n\t\t\tcompositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));\r\n\t\t}\r\n\t}\r\n\treaderContext.fireComponentRegistered(compositeDef);\r\n}\r\n<\/pre>\n<p>The registration of <em><\/em> is delegated to <strong>AnnotationConfigUtils<\/strong>.<em>registerAnnotationConfigProcessors()<\/em><\/p>\n<h5>\n2) org.springframework.context.annotation.<strong>AnnotationConfigUtils<\/strong><br \/>\n<\/h5>\n<p><strong> Point A<\/strong><\/p>\n<pre class=\"brush: java; highlight: [1,2,4,5,6,7,8,9,10,11,12,13,47,53,54]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =\r\n            &quot;org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor&quot;;\r\n\r\n            \/*\r\n             * Check for JPA support\r\n             * \r\n             * JPA is present if classes \r\n             *\r\n             *  1) &quot;org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor&quot;\r\n             *  2) &quot;javax.persistence.EntityManagerFactory&quot;\r\n             *\r\n             * are detected in the Spring context\r\n             *\/\r\n\r\n  private static final boolean jpaPresent = \r\n            ClassUtils.isPresent(&quot;javax.persistence.EntityManagerFactory&quot;,\r\n            AnnotationConfigUtils.class.getClassLoader()) \r\n            &amp;amp;&amp;amp;\r\n            ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,\r\n            AnnotationConfigUtils.class.getClassLoader());\r\n\r\n  \/\/ Point A\r\n  public static Set&lt;BeanDefinitionHolder&gt; registerAnnotationConfigProcessors(\r\n            BeanDefinitionRegistry registry, Object source) {\r\n\r\n   Set&lt;BeanDefinitionHolder&gt; beanDefs = new LinkedHashSet&lt;BeanDefinitionHolder&gt;(4);\r\n\r\n   if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {\r\n       RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);\r\n       def.setSource(source);\r\n       beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));\r\n   }\r\n\r\n   if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {\r\n       RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);\r\n       def.setSource(source);\r\n       beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));\r\n    }\r\n\r\n    \u2026\r\n\r\n    \/\/ Check for JPA support and if present add the PersistenceAnnotationBeanPostProcessor \r\n    \/\/ (if not declared explicitely)\r\n    if (jpaPresent &amp;amp;&amp;amp; !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {\r\n        RootBeanDefinition def = new RootBeanDefinition();\r\n        try {\r\n            ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();\r\n            def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));\r\n        }\r\n        catch (ClassNotFoundException ex) {\r\n            throw new IllegalStateException(&quot;Cannot load optional framework class: &quot; \r\n                                   + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);\r\n        }\r\n        def.setSource(source);\r\n        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));\r\n    }\r\n    return beanDefs;\r\n  }\r\n<\/pre>\n<p>The registration is done here at <strong>lines 47, 53 &amp; 54<\/strong><br \/>\n&nbsp;<\/p>\n<h2>B Annotation processing<\/h2>\n<p>&nbsp;<\/p>\n<h5>\n1) org.springframework.orm.jpa.support.<strong>PersistenceAnnotationBeanPostProcessor<\/strong><br \/>\n<\/h5>\n<pre class=\"brush: java; highlight: [3,4,6,7,16,25,26,32,37,38,51]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException  {\r\n\r\n\t\/\/ (see Point B below) \r\n\tInjectionMetadata metadata = findPersistenceMetadata(bean.getClass());\r\n\ttry {\r\n\t\t\/\/ (see Point C) \r\n\t\tmetadata.inject(bean, beanName, pvs);\r\n\t}\r\n\tcatch (Throwable ex) {\r\n\t\tthrow new BeanCreationException(beanName, \r\n                          &quot;Injection of persistence dependencies failed&quot;, ex);\r\n\t}\r\n\treturn pvs;\r\n  }\r\n  \r\n  \/\/ Point B\r\n  private InjectionMetadata findPersistenceMetadata(final Class clazz) {\r\n        ...\r\n        \/\/ Not interesting code\r\n        ...\r\n\tdo {\r\n\t\tLinkedList&lt;InjectionMetadata.InjectedElement&gt; currElements = \r\n                                new LinkedList&lt;InjectionMetadata.InjectedElement&gt;();\r\n\t\tfor (Field field : targetClass.getDeclaredFields()) {\r\n\t\t\tPersistenceContext pc = field.getAnnotation(PersistenceContext.class);\r\n\t\t\tPersistenceUnit pu = field.getAnnotation(PersistenceUnit.class);\r\n\t\t\tif (pc != null || pu != null) {\r\n\t\t\t\tif (Modifier.isStatic(field.getModifiers())) {\r\n\t\t\t\t\tthrow new IllegalStateException(&quot;Persistence annotations \r\n                                                            are not supported on static fields&quot;);\r\n\t\t\t\t}\r\n\t\t\t\tcurrElements.add(new PersistenceElement(field, null));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (Method method : targetClass.getDeclaredMethods()) {\r\n\t\t\tPersistenceContext pc = method.getAnnotation(PersistenceContext.class);\r\n\t\t\tPersistenceUnit pu = method.getAnnotation(PersistenceUnit.class);\r\n\t\t\tif (pc != null || pu != null \r\n                          &amp;amp;&amp;amp; \t\t\t\t\t\t\t\r\n                        method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {\r\n\t\t\t\tif (Modifier.isStatic(method.getModifiers())) {\r\n\t\t\t\t\tthrow new IllegalStateException(&quot;Persistence annotations  \r\n                                                                are not supported on static methods&quot;);\r\n\t\t\t\t}\r\n\t\t\t\tif (method.getParameterTypes().length != 1) {\r\n\t\t\t\t\tthrow new IllegalStateException(&quot;Persistence annotation requires \r\n                                                                       a single-arg method: &quot; + method);\r\n\t\t\t\t}\r\n\t\t\t\tPropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);\r\n\t\t\t\tcurrElements.add(new PersistenceElement(method, pd));\r\n\t\t\t}\r\n\t\t}\r\n\t\telements.addAll(0, currElements);\r\n\t\ttargetClass = targetClass.getSuperclass();\r\n\t}\r\n\twhile (targetClass != null &amp;amp;&amp;amp; targetClass != Object.class);\r\n\r\n\tmetadata = new InjectionMetadata(clazz, elements);\r\n\tthis.injectionMetadataCache.put(clazz, metadata);\r\n        ...\r\n  return metadata;\r\n<\/pre>\n<p>The method <em>postProcessPropertyValues()<\/em> is called when the host bean is initialized because the <strong>PersistenceAnnotationBeanPostProcessor<\/strong> implements the <strong>InstantiationAwareBeanPostProcessor<\/strong> interface<\/p>\n<p>In <em>findPersistenceMetadata()<\/em>, the most interesting points are at <strong>lines 32 &amp; 51<\/strong> where Spring adds new <strong>PersistenceElement<\/strong> instances to the list of <strong>InjectionMetaData<\/strong><\/p>\n<h5>\n2) org.springframework.beans.factory.annotation.<strong>InjectionMetadata<\/strong><br \/>\n<\/h5>\n<p><strong>Point C<\/strong><\/p>\n<pre class=\"brush: java; highlight: [1,10,11,19,24,25]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  \/\/ Point C\r\n  public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {\r\n\tif (!this.injectedElements.isEmpty()) {\r\n\t\tboolean debug = logger.isDebugEnabled();\r\n\t\tfor (InjectedElement element : this.injectedElements) {\r\n\t\t\tif (debug) {\r\n\t\t\t\t\tlogger.debug(&quot;Processing injected method of bean '&quot; \r\n                                                             + beanName + &quot;': &quot; + element);\r\n\t\t\t}\r\n                        \/\/ (see Point D below)\r\n\t\t\telement.inject(target, beanName, pvs);\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\n  public static abstract class InjectedElement {\r\n  ...\r\n  \/\/ Point D\r\n  protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {\r\n\tif (this.isField) {\r\n\t\tField field = (Field) this.member;\r\n\t\tReflectionUtils.makeAccessible(field);\r\n\t\tfield.set(target, getResourceToInject(target, requestingBeanName));\r\n\t}\r\n\telse {\r\n\t\tif (checkPropertySkipping(pvs)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\ttry {\r\n\t\t\tMethod method = (Method) this.member;\r\n\t\t\tReflectionUtils.makeAccessible(method);\r\n                        \/\/ (see Point E)\r\n\t\t\tmethod.invoke(target, getResourceToInject(target, requestingBeanName));\r\n\t\t}\r\n\t\tcatch (InvocationTargetException ex) {\r\n\t\t\tthrow ex.getTargetException();\r\n\t\t}\r\n\t}\r\n  }\r\n  }\r\n<\/pre>\n<p>This class is just a code indirection to call <em>getResourceToInject()<\/em> on the <strong>PersistenceElement<\/strong> <\/p>\n<h5>\n3) org.springframework.orm.jpa.support.<strong>PersistenceAnnotationBeanPostProcessor<\/strong><br \/>\n<\/h5>\n<p><strong>Point E<\/strong><\/p>\n<pre class=\"brush: java; highlight: [3,6,7,8,9,10,11,14,15,21,28,33,36,39,40,41,52,59,62,70,71,88]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  private class PersistenceElement extends InjectionMetadata.InjectedElement\r\n\r\n  \/\/ Point E  \r\n  protected Object getResourceToInject(Object target, String requestingBeanName) {\r\n\r\n\t\/* \r\n\t * The type attribute(TRANSACTION or EXTENDED) is only available \r\n\t * for @PersistenceContext annotation\r\n\t * \r\n\t * Default type value is PersistenceContextType.TRANSACTION\r\n\t *\/ \r\n\tif (this.type != null) {\r\n\t\treturn (this.type == PersistenceContextType.EXTENDED ?\r\n\t\t\tresolveExtendedEntityManager(target, requestingBeanName) : \/\/See Point F below\r\n\t\t\tresolveEntityManager(requestingBeanName)); \/\/ See Point G below\r\n\t}\r\n\r\n\t\/\/ Case of @PersistenceUnit annotation\r\n\telse {\r\n\t\t\/\/ OK, so we need an EntityManagerFactory...\r\n\t\treturn resolveEntityManagerFactory(requestingBeanName); \/\/ See Point H below\r\n\t}\r\n}\r\n  \/\/ Point F\r\n  private EntityManager resolveExtendedEntityManager(Object target, String requestingBeanName) {\r\n\t\/\/ Obtain EntityManager reference from JNDI?\r\n\t\/\/ return a non null em only in a J2EE context\r\n\tEntityManager em = getPersistenceContext(this.unitName, true);\r\n\tif (em == null) {\r\n\t\t\/\/ No pre-built EntityManager found -&gt; build one based on factory.\r\n\t\t\/\/ Obtain EntityManagerFactory from JNDI?\r\n\t\t\/\/ return a non null emf only in a J2EE context\r\n\t\tEntityManagerFactory emf = getPersistenceUnit(this.unitName);\r\n\t\tif (emf == null) {\r\n\t\t\t\/\/ Need to search for EntityManagerFactory beans.\r\n\t\t\temf = findEntityManagerFactory(this.unitName, requestingBeanName);\r\n\t\t}\r\n\t\t\/\/ Inject a container-managed extended EntityManager.\r\n\t\t\/\/ (see Point I)\r\n\t\tem = ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf,\r\n                                                                         this.properties);\r\n\t}\r\n\tif (em instanceof EntityManagerProxy &amp;amp;&amp;amp;\tbeanFactory != null \r\n             &amp;amp;&amp;amp; !beanFactory.isPrototype(requestingBeanName)) {\r\n\t\textendedEntityManagersToClose.put(target, \r\n                ((EntityManagerProxy) em).getTargetEntityManager());\r\n\t}\r\n\treturn em;\r\n  }\r\n  \/\/ Point G\r\n  private EntityManager resolveEntityManager(String requestingBeanName) {\r\n\t\/\/ Obtain EntityManager reference from JNDI?\r\n\t\/\/ return a non null em only in a J2EE context\r\n\tEntityManager em = getPersistenceContext(this.unitName, false);\r\n\tif (em == null) {\r\n\t\t\/\/ No pre-built EntityManager found -&gt; build one based on factory.\r\n\t\t\/\/ Obtain EntityManagerFactory from JNDI?\r\n\t\t\/\/ return a non null emf only in a J2EE context\r\n\t\tEntityManagerFactory emf = getPersistenceUnit(this.unitName);\r\n\t\tif (emf == null) {\r\n\t\t\t\/\/ Need to search for EntityManagerFactory beans.\r\n\t\t\temf = findEntityManagerFactory(this.unitName, requestingBeanName);\r\n\t\t}\r\n\t\t\/\/ Inject a shared transactional EntityManager proxy.\r\n\t\tif (emf instanceof EntityManagerFactoryInfo &amp;amp;&amp;amp;\r\n\t\t\t((EntityManagerFactoryInfo) emf).getEntityManagerInterface() != null) {\r\n\r\n\t\t\t\/\/ Create EntityManager based on the info's vendor-specific type\r\n\t\t\t\/\/ (which might be more specific than the field's type).\r\n\t\t\t\/\/ (see Point J)\r\n\t\t\tem = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties);\r\n\t\t}\r\n\t\telse {\r\n\t\t\t\/\/ Create EntityManager based on the field's type.\r\n\t\t\tem = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties,\r\n                                                                                   getResourceType());\r\n\t\t}\r\n\t}\r\n\treturn em;\r\n  }\r\n\r\n  \/\/ Point H\r\n  private EntityManagerFactory resolveEntityManagerFactory(String requestingBeanName) {\r\n\t\/\/ Obtain EntityManagerFactory from JNDI?\r\n\tEntityManagerFactory emf = getPersistenceUnit(this.unitName);\r\n\tif (emf == null) {\r\n\t\t\/\/ Need to search for EntityManagerFactory beans.\r\n\t\temf = findEntityManagerFactory(this.unitName, requestingBeanName);\r\n\t}\r\n\treturn emf;\r\n  }\r\n<\/pre>\n<p>Analysis of <em>getResourceToInject()<\/em> method:<\/p>\n<ul>\n<li>If the type attribute is not null, we are facing a <strong>@PersistenceContext<\/strong> annotation. Two possible values for the type: TRANSACTION (default value) and EXTENDED\n<ul>\n<li>If type = TRANSACTION, call <em>resolveEntityManager()<\/em> (<strong>line 15<\/strong>)<\/li>\n<li>Else (type = EXTENDED) call <em>resolveExtendedEntityManager()<\/em> (<strong>line 14<\/strong>)\n    <\/li>\n<\/ul>\n<\/li>\n<li>Else we are facing a <strong>@PersistenceUnit<\/strong> annotation, call <em>resolveEntityManagerFactory<\/em> (<strong>line 21<\/strong>)\n  <\/li>\n<\/ul>\n<p>For both <em>resolveEntityManager()<\/em> &amp; <em>resolveExtendedEntityManager()<\/em>  methods:<\/p>\n<ul>\n<li><em>getPersistenceContext()<\/em> returns a <strong>null<\/strong> object in non J2EE platform<\/li>\n<li><em>getPersistenceUnit()<\/em> returns a <strong>null<\/strong> object in non J2EE platform<\/li>\n<li><em>findEntityManagerFactory()<\/em> returns the entity manager factory associated to declared <em>unitName<\/em>\n<ul>\n<li>If the <em>unitName<\/em> attribute of the <strong>@PersistenceContext\/@PersistenceUnit<\/strong> was specified, use it to look up the entity manager factory\n      <\/li>\n<li>Else find the default entity manager factory (name = <em>&#8220;entityManagerFactory&#8221;<\/em> by convention)\n      <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>In the EXTENDED <strong>@PersistenceContext<\/strong> case, call <strong>ExtendedEntityManagerCreator<\/strong>.<em>createContainerManagedEntityManager()<\/em> (<strong>lines 40 &amp; 41<\/strong>)<\/li>\n<p>&nbsp;<\/p>\n<li>In the default <strong>@PersistenceContext<\/strong> case, call <strong>SharedEntityManagerCreator<\/strong>.<em>createSharedEntityManager()<\/em> (<strong>lines 70 &amp; 71<\/strong>)<\/li>\n<p>&nbsp;<\/p>\n<li>In the <strong>@PersistenceUnit<\/strong> case, call <em>findEntityManagerFactory()<\/em><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h5>\n4) org.springframework.orm.jpa.<strong>ExtendedEntityManagerCreator<\/strong><br \/>\n<\/h5>\n<p><strong>Point I<\/strong><\/p>\n<pre class=\"brush: java; highlight: [1,8,13]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  \/\/ Point I\r\n  public static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf, Map properties) {\r\n\tAssert.notNull(emf, &quot;EntityManagerFactory must not be null&quot;);\r\n\tif (emf instanceof EntityManagerFactoryInfo) {\r\n\t\tEntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;\r\n\t\tEntityManagerFactory nativeEmf = emfInfo.getNativeEntityManagerFactory();\r\n\t\tEntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ?\r\n\t\t\tnativeEmf.createEntityManager(properties) : nativeEmf.createEntityManager());\r\n\t\treturn createProxy(rawEntityManager, emfInfo, true);\r\n\t}\r\n\telse {\r\n\t\tEntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ?\r\n\t\t\temf.createEntityManager(properties) : emf.createEntityManager());\r\n\t\treturn createProxy(rawEntityManager, null, null, null, null, null, true);\r\n\t}\r\n  }\r\n<\/pre>\n<p>This class is quite straighforward. It creates a new  <strong>EntityManager<\/strong> instance using the entity manager factory and returns it (<strong>lines 8 &amp; 13<\/strong>).<\/p>\n<h5>\n5) org.springframework.orm.jpa.<strong>SharedEntityManagerCreator<\/strong><br \/>\n<\/h5>\n<p><strong>Point J, Point K &amp; Point L<\/strong><\/p>\n<pre class=\"brush: java; highlight: [1,7,10,23,24,25,28,50,51,52,55,56,57,62,63,64,73,77,78,84,94,95]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  \/\/ Point J\r\n  public static EntityManager createSharedEntityManager(EntityManagerFactory emf, Map properties) {\r\n\tClass[] emIfcs;\r\n\t...\r\n\t\/\/ Not interesting code\r\n\t...\r\n\treturn createSharedEntityManager(emf, properties, emIfcs); \/\/ See Point K below\r\n  }\r\n\r\n  \/\/ Point K\r\n  public static EntityManager createSharedEntityManager(\r\n\tEntityManagerFactory emf, Map properties, Class... entityManagerInterfaces) {\r\n\r\n\tClassLoader cl = null;\r\n\tif (emf instanceof EntityManagerFactoryInfo) {\r\n\t\tcl = ((EntityManagerFactoryInfo) emf).getBeanClassLoader();\r\n\t}\r\n\tClass[] ifcs = new Class[entityManagerInterfaces.length + 1];\r\n\tSystem.arraycopy(entityManagerInterfaces, 0, ifcs, 0, entityManagerInterfaces.length);\r\n\tifcs[entityManagerInterfaces.length] = EntityManagerProxy.class;\r\n\r\n\t\/\/ Returns a proxy of EntityManager with a SharedEntityManagerInvocationHandler as callback\r\n\treturn (EntityManager) Proxy.newProxyInstance(\r\n\t\t(cl != null ? cl : SharedEntityManagerCreator.class.getClassLoader()),\r\n\t\tifcs, new SharedEntityManagerInvocationHandler(emf, properties)); \/\/ See Point L below\r\n  }\r\n\r\n  \/\/ Point L\r\n  private static class SharedEntityManagerInvocationHandler implements InvocationHandler, Serializable {\r\n\t...\r\n\t\/\/ Not interesting code\r\n\t...\r\n\r\n  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\r\n\t...\r\n\t\/\/ Not interesting code\r\n\t...\r\n\telse if (method.getName().equals(&quot;toString&quot;)) {\r\n\t\t\/\/ Deliver toString without touching a target EntityManager.\r\n\t\treturn &quot;Shared EntityManager proxy for target factory [&quot; + this.targetFactory + &quot;]&quot;;\r\n\t}\r\n\t\r\n\telse if (method.getName().equals(&quot;getEntityManagerFactory&quot;)) {\r\n\t\t\/\/ JPA 2.0: return EntityManagerFactory without creating an EntityManager.\r\n\t\treturn this.targetFactory;\r\n\t}\r\n\t...\r\n\t\/\/ Not interesting code\r\n\t...\r\n\telse if (method.getName().equals(&quot;getTransaction&quot;)) {\r\n\t\tthrow new IllegalStateException(&quot;Not allowed to create transaction on shared&quot; \r\n                               +&quot; EntityManager - use Spring transactions or EJB CMT instead&quot;);\r\n\t}\r\n\t\r\n\telse if (method.getName().equals(&quot;joinTransaction&quot;)) {\r\n\t\tthrow new IllegalStateException(&quot;Not allowed to join transaction on shared &quot; \r\n\t\t\t       +&quot; EntityManager - use Spring transactions or EJB CMT instead&quot;);\r\n\t}\r\n\r\n\t\/\/ Determine current EntityManager: either the transactional one\r\n\t\/\/ managed by the factory or a temporary one for the given invocation.\r\n\t\/\/ (see Point M)         \r\n\tEntityManager target =\tEntityManagerFactoryUtils.doGetTransactionalEntityManager(\r\n                                this.targetFactory, this.properties);\r\n\r\n\t...\r\n\t\/\/ Not interesting code\r\n\t...\r\n\r\n\t\/\/ Regular EntityManager operations.\r\n\tboolean isNewEm = false;\r\n\r\n\t\/\/ USE CASE 1: @PersistenceContext used with NON @Transactional method\r\n\tif (target == null) {\r\n\t\tlogger.debug(&quot;Creating new EntityManager for shared EntityManager invocation&quot;);\r\n\t\ttarget = (!CollectionUtils.isEmpty(this.properties) ?\r\n\t\t\tthis.targetFactory.createEntityManager(this.properties) :\r\n\t\t\tthis.targetFactory.createEntityManager());\r\n\t\tisNewEm = true;\r\n\t}\r\n\r\n\t\/\/ Invoke method on current EntityManager.\r\n\ttry {\r\n\t\tObject result = method.invoke(target, args);\r\n\r\n\t\t...\r\n\t\t\/\/ Not interesting code\r\n\t\t...\r\n\r\n\tcatch (InvocationTargetException ex) {\r\n\t\tthrow ex.getTargetException();\r\n\t}\r\n\tfinally {\r\n\t\tif (isNewEm) {\r\n\t\t\tEntityManagerFactoryUtils.closeEntityManager(target);\r\n\t\t}\r\n\t}\r\n  }\r\n<\/pre>\n<p>Many interesting points in this class<\/p>\n<ul>\n<li><strong>Lines 23, 24 &amp; 25<\/strong>, Spring wraps a proxy object around the class <strong>SharedEntityManagerInvocationHandler<\/strong><\/li>\n<p>  &nbsp;<\/p>\n<li>In the <strong>SharedEntityManagerInvocationHandler<\/strong>.<em>invoke()<\/em> method:\n<ul>\n<li><em>getTransaction()<\/em> is not allowed because the transaction is managed by Spring using @Transactional annotation <strong>(lines 50, 51 &amp; 52)<\/strong><\/li>\n<li>Similarly, <em>joinTransaction()<\/em> is not allowed  <strong>(lines 55, 56 &amp; 57)<\/strong><\/li>\n<li>The entityManager is retrieved by calling  <strong>EntityManagerFactoryUtils<\/strong>.<em>doGetTransactionalEntityManager()<\/em><\/li>\n<li>If the retrived entityManager is <strong>null<\/strong>, it corresponds to <strong>USE CASE 1<\/strong> where the <strong>@PersistenceContext<\/strong> is used within <strong>NON @Transactional<\/strong> method. In this case Spring will create a new EntityManager instance from scratch <strong>(lines 77 &amp; 78)<\/strong><\/li>\n<li>At the end of the method invocation, if the EntityManager was created from scratch, it is automatically closed by Spring  <strong>(lines 94 &amp; 95)<\/strong>. This is the <em>session-per-request<\/em> pattern<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n&nbsp;<\/p>\n<h5>\n6) org.springframework.orm.jpa.<strong>EntityManagerFactoryUtils<\/strong><br \/>\n<\/h5>\n<p><strong>Point M<\/strong><\/p>\n<pre class=\"brush: java; highlight: [1,8,9,20,28,34,41,42,48,51,52,58,61]; title: ; toolbar: false; wrap-lines: false; notranslate\" title=\"\">\r\n  \/\/ Point M\r\n  public static EntityManager doGetTransactionalEntityManager(\r\n\tEntityManagerFactory emf, Map properties) throws PersistenceException {\r\n\tAssert.notNull(emf, &quot;No EntityManagerFactory specified&quot;);\r\n\r\n\t\/\/ Try to get existing EntityManagerHolder from the TransactionSynchronizationManager \r\n\t\/\/ ThreadLocal map using the EntityManagerFactory as search key\r\n\tEntityManagerHolder emHolder =\r\n\t\t\t\t(EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);\r\n\r\n\tif (emHolder != null) {\r\n\t\tif (!emHolder.isSynchronizedWithTransaction() &amp;amp;&amp;amp;\r\n\t\t\tTransactionSynchronizationManager.isSynchronizationActive()) {\r\n\t\t\t\/\/ Try to explicitly synchronize the EntityManager itself\r\n\t\t\t\/\/ with an ongoing JTA transaction, if any.\r\n\t\t\ttry {\r\n\t\t\t\t\/\/ CASE 3 @PersistenceContext used within nested @Transactional methods \r\n\t\t\t\t\/\/ Join existing transaction, do not create a new EntityManager\r\n\t\t\t\t\/\/ (when @Transactional method is calling  other @Transactional methods)\r\n\t\t\t\temHolder.getEntityManager().joinTransaction();\r\n\t\t\t}\r\n\t\t\tcatch (TransactionRequiredException ex) {\r\n\t\t\t\tlogger.debug(&quot;Could not join JTA transaction because none was active&quot;, ex);\r\n\t\t\t}\r\n\t\t\t...\r\n\t\t\t\/\/ Not interesting code\r\n\t\t\t...\r\n\t\t\treturn emHolder.getEntityManager();\r\n\t\t}\r\n\r\n\t\t\/\/ USE CASE 1: @PersistenceContext used with NON @Transactional method\r\n\t\tif (!TransactionSynchronizationManager.isSynchronizationActive()) {\r\n\t\t\t\/\/ Indicate that we can't obtain a transactional EntityManager.\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t\/\/ Create a new EntityManager for use within the current transaction.\r\n\t\t\/\/ USE CASE 2: @PersistenceContext used within a @Transactional method \r\n                \/\/ linked to another TransactionManager\r\n\t\tlogger.debug(&quot;Opening JPA EntityManager&quot;);\r\n\t\tEntityManager em = (!CollectionUtils.isEmpty(properties) ? \r\n\t\t\t\temf.createEntityManager(properties) : emf.createEntityManager());\r\n\r\n\t\tif (TransactionSynchronizationManager.isSynchronizationActive()) {\r\n\t\t\tlogger.debug(&quot;Registering transaction synchronization for JPA EntityManager&quot;);\r\n\t\t\t\/\/ Use same EntityManager for further JPA actions within the transaction.\r\n\t\t\t\/\/ Thread object will get removed by synchronization at transaction completion.\r\n\t\t\temHolder = new EntityManagerHolder(em);\r\n\t\t\tObject transactionData = prepareTransaction(em, emf);\r\n\r\n\t\t\tTransactionSynchronizationManager.registerSynchronization(\t\t\t\r\n\t\t\t\tnew EntityManagerSynchronization(emHolder, emf, transactionData, true));\r\n\t\t\temHolder.setSynchronizedWithTransaction(true);\r\n\r\n\t\t\t\/\/ Register the newly created EntityManager in the \r\n\t\t\t\/\/ TransactionSynchronizationManager map\r\n\t\t\t\/\/ using the EntityManagerFactory as search key\r\n\t\t\tTransactionSynchronizationManager.bindResource(emf, emHolder);\r\n\t\t}\r\n\r\n\t\treturn em;\r\n\t}\r\n<\/pre>\n<p>The core of the EntityManager injection is done in this class<\/p>\n<\/ul>\n<ul>\n<li>First Spring will look into the <strong>TransactionSynchronizationManager<\/strong> ThreadLocal map to check if there is a bound EntityManager <strong>(lines 8 &amp; 9)<\/strong>\n  <\/li>\n<li>If a bound EntityManager is found, Spring just joins the existing transaction <strong>(lines 20)<\/strong> and returns this EntityManager instance <strong>(line 28)<\/strong>. This is <strong>USE CASE 3<\/strong> when <strong>@PersistenceContext<\/strong> is used within nested <strong>@Transactional<\/strong> methods<\/li>\n<li>If <strong>TransactionSynchronizationManager<\/strong>.<em>isSynchronizationActive()<\/em> is false, it means that the <strong>@PersistenceContext<\/strong> is used with NON <strong>@Transactional<\/strong> method. This is <strong>USE CASE 1<\/strong>. Spring simply retuns <strong>null<\/strong> so the  <strong>SharedEntityManagerCreator<\/strong> will create itself a new EntityManager instance, see  <strong>line 73<\/strong> of <strong>Point L<\/strong><\/li>\n<p>  &nbsp;<\/p>\n<li>The last case is <strong>USE CASE 2<\/strong> when <strong>@PersistenceContext<\/strong> is used within a <strong>@Transactional<\/strong> method but linked to another TransactionManager. Spring will:\n<ul>\n<li>Create a new EntityManager instance from scratch <strong>(lines 41 &amp; 42)<\/strong><\/li>\n<li>Wrap an EntityManagerHolder around it <strong>(line 48)<\/strong><\/li>\n<li>Register the synchronization with the <strong>TransactionSynchronizationManager<\/strong> <strong>(lines 51 &amp; 52)<\/strong><\/li>\n<li>Bind this EntityManagerHolder to the <strong>TransactionSynchronizationManager<\/strong> ThreadLocal map <strong>(line 58)<\/strong><\/li>\n<li>Return this EntityManager <strong>(line 61)<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<blockquote><p>Please note that in this case, the EntityManager created by Spring <strong>will not participate in the transaction<\/strong> created by Spring <em>@Transactional(value=&#8221;anotherTransactionManager&#8221;)<\/em> because this transaction is registed with the EntityManager created with respect to the declared <strong>anotherTransactionManager<\/strong>. Consequently, <strong>any DML operation will be simply rolled back at the end of the transaction<\/strong> for this particular EntityManager<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h1>IV Summary<\/h1>\n<p>&nbsp;<\/p>\n<ul>\n<li>USE CASE 1: <strong>@PersistenceContext<\/strong> used with NON <strong>@Transactional<\/strong> method\n<ul>\n<li>Create an <strong>EntityManager<\/strong> instance directly from the <strong>EntityManagerFactory<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>USE CASE 2: <strong>@PersistenceContext<\/strong> used with <strong>@Transactional method declared for another persistenceUnit<\/strong>\n<ul>\n<li>Create an <strong>EntityManager<\/strong> instance directly from the <strong>EntityManagerFactory<\/strong> and register it with            <strong>TransactionSynchronizationManager<\/strong>.<em>bindResource(emf, emHolder)<\/em> for later use<\/li>\n<\/ul>\n<\/li>\n<li>USE CASE 3: <strong>@PersistenceContext<\/strong> used within nested <strong>@Transactional<\/strong> methods\n<ul>\n<li>Retrieve an existing <strong>EntityManager<\/strong> instance from  <strong>TransactionSynchronizationManager<\/strong>.<em>getResource(emf)<\/em> using the <strong>EntityManagerFactory<\/strong> as search key<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<br \/>\nAgain, we can see in this code analysis the key role of the <strong>TransactionSynchronizationManager<\/strong> managing the lifecycle of EntityManager instances.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the 2nd article of a serie on Spring code analysis. Today we are going to dig into the @PersistenceContext annotation, widely used by JPA\/Hibernate developers to inject an Entity Manager into their DAO classes.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[7,29,14],"tags":[36,40,43],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/222"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=222"}],"version-history":[{"count":3,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/222\/revisions"}],"predecessor-version":[{"id":13535,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/222\/revisions\/13535"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}