Spring Data之EntityManagerFactory创建及源码分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

背景

Spring Data之JPA开篇中可以看到Spring Boot的启动日志,先是创建了HikariDataSource,然后紧接着构建了EntityManagerFactory

    2018-10-25 09:32:20.645  INFO 37469 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
    2018-10-25 09:32:20.791  INFO 37469 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
    2018-10-25 09:32:20.846  INFO 37469 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'

其中HikariDataSource的创建在Spring Data之DataSource创建及源码分析中进行了介绍,这篇文章我们就来探寻一下EntityManagerFactory是如何自动创建出来的。

JPA规范

首先有必要了解一下JPA规范(JSR 338)以便更好的理解EntityManagerFactory的创建过程。

JSR 338主要定义了如何通过普通的Java domain进行关系数据库的操作及映射,其中主要概念包含如下:

  • Entity

    • 必须是顶级类
    • @Entity注解的类
    • 必须有一个无参的public 或 protected的构造方法
    • 不能是final类,且不能有final方法或final变量
    • 一个Entity类通常与数据库的一张表进行对应
    • 一个Entity实例表现为数据库的一条数据
    • 对Entity的操作即对数据库的操作
    • 生命周期包含初始、托管、释放、消亡
  • EntityManager

    • 对Entity持久化操作的主要对象
    • 通过EntityManagerFactory获取实例
    • 一个实例代表一个数据库连接
    • 每个线程拥有自己的EntityManager实例
    • 主要方法有persist、remove、merge、createQuery、find
    • 可使用@PersistenceContext注入
  • EntityManagerFactory

    • 创建EntityManager的工厂
    • EntityManagerFactory的创建成本很高,对于给定的数据库,系统应该只创建一个与之关联的Factory
    • 可使用@PersistenceUnit注入
  • EntityTransaction

    • 表示数据库事务,在增、删、改时使用
    • 可通过EntityManager.getTransaction()获取
  • Persistence Context

    • 维护一组托管状态的Entity实例
    • 与EntityManager是相关联的
  • Persistence Unit

    • 一组Entity及相关设置的逻辑单元
    • 定义创建EntityManagerFactory所需要的参数
    • 通过persistence.xml定义或者通过一个PersistenceUnitInfo对象

总结一下,通过Persistence Unit创建EntityManagerFactory,再通过EntityManagerFactory获取EntityManager。下面我们就按照这个方向进行源码分析。

自动配置

同DataSource一样,EntityManagerFactory的创建也是通过一些列@Conditional的注解最终找到Hibernate的实现。我们先看下自动配置的入口类HibernateJpaAutoConfiguration

    @Configuration
    //先校验是否存在LocalContainerEntityManagerFactoryBean
    //该类是spring-orm包中的类,从名称上看就知道是跟EntityManagerFactory的创建有关的
    //要使用JPA,EntityManager自然也是要存在的
    @ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class })
    //自定义的校验类,校验是否存在CLASS_NAMES中的类
    @Conditional(HibernateEntityManagerCondition.class)
    //在application.properties中配置的spring.jpa开头的设置,会注入到JpaProperties中
    //换句话说在spring.jpa能设置什么,要看JpaProperties有什么属性
    @EnableConfigurationProperties(JpaProperties.class)
    //这个设置很关键,意思是要在DataSource之后再创建,因为JPA会用到DataSource
    @AutoConfigureAfter({ DataSourceAutoConfiguration.class })
    //上面的校验都满足后,则进入HibernateJpaConfiguration
    @Import(HibernateJpaConfiguration.class)
    public class HibernateJpaAutoConfiguration {

        @Order(Ordered.HIGHEST_PRECEDENCE + 20)
        static class HibernateEntityManagerCondition extends SpringBootCondition {

            private static final String[] CLASS_NAMES = {
                    "org.hibernate.ejb.HibernateEntityManager",
                    "org.hibernate.jpa.HibernateEntityManager" };

            /** * 通过ClassUtils.isPresent检查是否存在CLASS_NAMES中指定的类 */
            @Override
            public ConditionOutcome getMatchOutcome(ConditionContext context,
                    AnnotatedTypeMetadata metadata) {
                ConditionMessage.Builder message = ConditionMessage
                        .forCondition("HibernateEntityManager");
                for (String className : CLASS_NAMES) {
                    if (ClassUtils.isPresent(className, context.getClassLoader())) {
                        return ConditionOutcome
                                .match(message.found("class").items(Style.QUOTE, className));
                    }
                }
                return ConditionOutcome.noMatch(message.didNotFind("class", "classes")
                        .items(Style.QUOTE, Arrays.asList(CLASS_NAMES)));
            }
        }
    }

主要逻辑已在代码中添加注释说明,接下来就看下@Import的HibernateJpaConfiguration

    @Configuration
    @ConditionalOnSingleCandidate(DataSource.class)
    class HibernateJpaConfiguration extends JpaBaseConfiguration {
        //省略。。。

        @Override
        protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
            return new HibernateJpaVendorAdapter();
        }

        //省略。。。
    }

省略了一些不重要的代码,只留下createJpaVendorAdapter方法。再接着看父类JpaBaseConfiguration

    @EnableConfigurationProperties(JpaProperties.class)
    @Import(DataSourceInitializedPublisher.Registrar.class)
    public abstract class JpaBaseConfiguration implements BeanFactoryAware {

        private final DataSource dataSource;

        private final JpaProperties properties;

        private final JtaTransactionManager jtaTransactionManager;

        private final TransactionManagerCustomizers transactionManagerCustomizers;

        private ConfigurableListableBeanFactory beanFactory;

        protected JpaBaseConfiguration(DataSource dataSource, JpaProperties properties,
                ObjectProvider<JtaTransactionManager> jtaTransactionManager,
                ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
            this.dataSource = dataSource;
            this.properties = properties;
            this.jtaTransactionManager = jtaTransactionManager.getIfAvailable();
            this.transactionManagerCustomizers = transactionManagerCustomizers
                    .getIfAvailable();
        }

        @Bean
        @ConditionalOnMissingBean
        public PlatformTransactionManager transactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            if (this.transactionManagerCustomizers != null) {
                this.transactionManagerCustomizers.customize(transactionManager);
            }
            return transactionManager;
        }

        @Bean
        @ConditionalOnMissingBean
        public JpaVendorAdapter jpaVendorAdapter() {
            AbstractJpaVendorAdapter adapter = createJpaVendorAdapter();
            adapter.setShowSql(this.properties.isShowSql());
            adapter.setDatabase(this.properties.determineDatabase(this.dataSource));
            adapter.setDatabasePlatform(this.properties.getDatabasePlatform());
            adapter.setGenerateDdl(this.properties.isGenerateDdl());
            return adapter;
        }

        @Bean
        @ConditionalOnMissingBean
        public EntityManagerFactoryBuilder entityManagerFactoryBuilder(
                JpaVendorAdapter jpaVendorAdapter,
                ObjectProvider<PersistenceUnitManager> persistenceUnitManager) {
            EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(
                    jpaVendorAdapter, this.properties.getProperties(),
                    persistenceUnitManager.getIfAvailable());
            builder.setCallback(getVendorCallback());
            return builder;
        }

        @Bean
        @Primary
        @ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class,
                EntityManagerFactory.class })
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                EntityManagerFactoryBuilder factoryBuilder) {
            Map<String, Object> vendorProperties = getVendorProperties();
            customizeVendorProperties(vendorProperties);
            return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan())
                    .properties(vendorProperties).mappingResources(getMappingResources())
                    .jta(isJta()).build();
        }

        protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();

    }

可以看到该类有4个@Bean注解的方法,咱们按顺序分析

  1. transactionManager
    创建JPA事务的管理器
  2. jpaVendorAdapter
    JpaVendorAdapter是一个接口,里面有一个方法是getPersistenceProvider,而PersistenceProvider是JPA规范中定义的创建EntityManagerFactory的接口方法。
    createJpaVendorAdapter的实现是在HibernateJpaConfiguration中返回的是 HibernateJpaVendorAdapter.

        public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter{
           private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect();
    
           private final PersistenceProvider persistenceProvider;
    
           private final Class entityManagerFactoryInterface;
    
           private final Class entityManagerInterface;
    
          /** * 明确指明了persistenceProvider的实现是SpringHibernateJpaPersistenceProvider */
           @SuppressWarnings("deprecation")
           public HibernateJpaVendorAdapter() {
               this.persistenceProvider = new SpringHibernateJpaPersistenceProvider();
               this.entityManagerFactoryInterface = org.hibernate.jpa.HibernateEntityManagerFactory.class;
               this.entityManagerInterface = org.hibernate.jpa.HibernateEntityManager.class;
           }
        }
    
        /** * 继承了Hibernate的PersistenceProvider */
        class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider{
    
           /** * 重要方法,调用了Hibernate的EntityManagerFactoryBuilderImpl,通过build创建出了EntityManagerFactory */
           public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) {
            final List mergedClassesAndPackages = new ArrayList<>(info.getManagedClassNames());
            if (info instanceof SmartPersistenceUnitInfo) {
                mergedClassesAndPackages.addAll(((SmartPersistenceUnitInfo) info).getManagedPackages());
            }
            return new EntityManagerFactoryBuilderImpl(
                    new PersistenceUnitInfoDescriptor(info) {
                        @Override
                        public List getManagedClassNames() {
                            return mergedClassesAndPackages;
                        }
                    }, properties).build();
           }
        }
    
  3. entityManagerFactoryBuilder
    建造者模式,将需要的原料都准备好
  4. entityManagerFactory
    LocalContainerEntityManagerFactoryBean就是启动日志中打印出*Building JPA container EntityManagerFactory for persistence unit ‘default’*的类。
    该类及其父类AbstractEntityManagerFactoryBean包含了创建EntityManagerFactory的所有元素,前面的步骤都是在为LocalContainerEntityManagerFactoryBean的属性准备数据赋值

        public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean
           implements ResourceLoaderAware, LoadTimeWeaverAware {
            /** *根据provider(前面提到的SpringHibernateJpaPersistenceProvider)创建EntityManagerFactory */
            protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
            Assert.state(this.persistenceUnitInfo != null, "PersistenceUnitInfo not initialized");
    
            PersistenceProvider provider = getPersistenceProvider();
            if (provider == null) {
                String providerClassName = this.persistenceUnitInfo.getPersistenceProviderClassName();
                if (providerClassName == null) {
                    throw new IllegalArgumentException(
                            "No PersistenceProvider specified in EntityManagerFactory configuration, " +
                            "and chosen PersistenceUnitInfo does not specify a provider class name either");
                }
                Class providerClass = ClassUtils.resolveClassName(providerClassName, getBeanClassLoader());
                provider = (PersistenceProvider) BeanUtils.instantiateClass(providerClass);
            }
    
            if (logger.isInfoEnabled()) {
                logger.info("Building JPA container EntityManagerFactory for persistence unit '" +
                        this.persistenceUnitInfo.getPersistenceUnitName() + "'");
            }
            EntityManagerFactory emf =
                    provider.createContainerEntityManagerFactory(this.persistenceUnitInfo, getJpaPropertyMap());
            postProcessEntityManagerFactory(emf, this.persistenceUnitInfo);
    
            return emf;
           }
        }
    

需要注意的是AbstractEntityManagerFactoryBean有两个EntityManagerFactory类型的属性,一个是通过PersistenceProvider获取的原生对象,另一个是Spring创建的代理对象ManagedEntityManagerFactoryInvocationHandler,它的目的是为了拦截EntityManager的创建,至少为什么要代理,下篇文档会进行分析。

结束语

到这里EntityManagerFactory就创建出来了,总的来说整个过程是遵循JPA规范定义的接口的,例如SpringHibernateJpaPersistenceProvider实现的createContainerEntityManagerFactory方法。只不过Spring作为骨干框架,使用了很多中间对象和过程。
最后用一张类图,再串一下创建的过程
20191102100722\_1.png

  1. 首先以左下角的HibernateJpaAutoConfiguration为入口,经过@Conditional的判断,@Import进入HibernateJpaConfiguration
  2. 在HibernateJpaConfiguration中依赖类HibernateJpaVendorAdapter,而HibernateJpaVendorAdapter又依赖了SpringHibernateJpaPersistenceProvider,PersistenceProvider的具体实现就确定了
  3. 在JpaBaseConfiguration中通过EntityManagerFactoryBuilder创建出了LocalContainerEntityManagerFactoryBean,该类是整个结构的纽带。可以看到它关联了PersistenceProvider和PersistenceUnitManager,而PersistenceUnitManager是产生PersistenceUnitInfo的,PersistenceProvider和PersistenceUnitInfo是createEntityFactory的两个必要对象
  4. 最后在LocalContainerEntityManagerFactoryBean中调用SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory创建出了EntityManagerFactory

那么EntityManagerFactory创建出来后有什么用呢,当然是用来获取EntityManager,下篇文章我们继续分析EntityManager的创建过程。


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Data之EntityManagerFactory创建及源码分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏