二十五摔蓝、Spring Boot中spring-data-jpa自動配置源碼分析

在上一節(jié)中赂苗,我們簡單的講述了jpa的查詢語法和使用教程,而這一節(jié)咱們來看看Spring Boot中對jpa是如何進(jìn)行自動配置的贮尉。

?

在Spring Boot自動配置的時候拌滋,一旦引入spring-boot-starter-data-jpa,就會完成JpaRepositoriesAutoConfiguration的自動配置猜谚。

JpaRepositoriesAutoConfiguration

@Configuration
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class,
        JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import(JpaRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
public class JpaRepositoriesAutoConfiguration {}

spring-data-jpa底層使用的是Hibernate作為實現(xiàn)败砂,所以jpa的自動配置操作在Hibernate的自動配置之后。

@AutoConfigureAfter:表示在指定類完成后再進(jìn)行自動配置魏铅,所以來看HibernateJpaAutoConfiguration源碼昌犹。

咱們繼續(xù):

HibernateJpaAutoConfiguration

@Configuration
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class })
@Conditional(HibernateEntityManagerCondition.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {

    //other...
    
    public HibernateJpaAutoConfiguration(DataSource dataSource,
            JpaProperties jpaProperties,
            ObjectProvider<JtaTransactionManager> jtaTransactionManager,
            ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
        //調(diào)用父類的構(gòu)造方法
        super(dataSource, jpaProperties, jtaTransactionManager,
                transactionManagerCustomizers);
    }

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

    @Override
    protected Map<String, Object> getVendorProperties() {
        Map<String, Object> vendorProperties = new LinkedHashMap<String, Object>();
        vendorProperties.putAll(getProperties().getHibernateProperties(getDataSource()));
        return vendorProperties;
    }
    
    //other...
}

同樣在HibernateJpaAutoConfiguration的源碼中表示該自動配置需要在DataSourceAutoConfiguration完成后再進(jìn)行,之前在分析JdbcTemplateAutoConfiguration的源碼的時候已經(jīng)分析過DataSourceAutoConfiguration览芳,此處就不再講述斜姥,一筆帶過。

? 回想之前在使用Spring和JPA集成的時候沧竟,會配置一個jpaVendorAdapter屬性铸敏,一般使用HibernateJpaVendorAdapter作為JPA持久化實現(xiàn)廠商類。如下是spring和jpa集成時的部分配置:

<property name="jpaVendorAdapter">
    <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <!-- 該bean的屬性配置 -->
    </bean>
</property>

? 在JpaBaseConfiguration類中有個createJpaVendorAdapter()抽象方法悟泵,而在HibernateJpaAutoConfiguration類中進(jìn)行了重載杈笔,創(chuàng)建使用HibernateJpaVendorAdapter作為JPA底層持久化實現(xiàn)廠商。

咱們來看父類的源碼:

父類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();
    }

    //創(chuàng)建了TransactionManager的Bean
    @Bean
    @ConditionalOnMissingBean(PlatformTransactionManager.class)
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        if (this.transactionManagerCustomizers != null) {
            this.transactionManagerCustomizers.customize(transactionManager);
        }
        return transactionManager;
    }

    //創(chuàng)建了jpaVendorAdapter適配器糕非,并填充相應(yīng)屬性蒙具,最后返回
    @Bean
    @ConditionalOnMissingBean
    public JpaVendorAdapter jpaVendorAdapter() {
        //通過HibernateJpaAutoConfiguration子類創(chuàng)建HibernateJpaVendorAdapter適配器
        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;
    }

    //通過jpaVendorAdapter與其他配置信息創(chuàng)建Builder構(gòu)建器
    @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;
    }

    //創(chuàng)建LocalContainerEntityManagerFactoryBean的Bean,用于JPA的容器管理EntityManagerFactory
    @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).jta(isJta()).build();
    }

    //other...
}

在父類JpaBaseConfiguration中創(chuàng)建了幾個重要的Bean朽肥,這樣創(chuàng)建Bean的過程類似之前spring-jpa集成時使用的xml配置文件:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}"></property>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
    <property name="user" value="${jdbc.user}"></property>
    <property name="password" value="${jdbc.password}"></property>
    <property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property>
    <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>

<!-- 配置jpa的EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"></property>

    <!-- 配置jpa生產(chǎn)商的適配器 -->
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
    </property>

    <!-- 配置jpa的基本屬性 -->
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>

<!-- 配置SpringData -->
<jpa:repositories base-package="xxxxx包名" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"></jpa:repositories>

通過這幾步j(luò)ava配置禁筏,基本上就完成了之前spring-jpa集成所需的所有配置信息,當(dāng)然Spring Boot內(nèi)部做了很多工作鞠呈,這里就不再描述了融师。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚁吝,隨后出現(xiàn)的幾起案子旱爆,更是在濱河造成了極大的恐慌,老刑警劉巖窘茁,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怀伦,死亡現(xiàn)場離奇詭異,居然都是意外死亡山林,警方通過查閱死者的電腦和手機(jī)房待,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人桑孩,你說我怎么就攤上這事拜鹤。” “怎么了流椒?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵敏簿,是天一觀的道長。 經(jīng)常有香客問我宣虾,道長惯裕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任绣硝,我火速辦了婚禮蜻势,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹉胖。我一直安慰自己握玛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布次员。 她就那樣靜靜地躺著败许,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淑蔚。 梳的紋絲不亂的頭發(fā)上市殷,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音刹衫,去河邊找鬼醋寝。 笑死,一個胖子當(dāng)著我的面吹牛带迟,可吹牛的內(nèi)容都是我干的音羞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仓犬,長吁一口氣:“原來是場噩夢啊……” “哼嗅绰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起搀继,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窘面,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后叽躯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體财边,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年点骑,在試婚紗的時候發(fā)現(xiàn)自己被綠了酣难。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谍夭。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖憨募,靈堂內(nèi)的尸體忽然破棺而出紧索,到底是詐尸還是另有隱情,我是刑警寧澤馋嗜,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布齐板,位于F島的核電站吵瞻,受9級特大地震影響葛菇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜橡羞,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一眯停、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卿泽,春花似錦莺债、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至第租,卻和暖如春措拇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背慎宾。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工丐吓, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人趟据。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓券犁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親汹碱。 傳聞我的和親對象是個殘疾皇子粘衬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容