欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring注解 @PropertySource配置數(shù)據(jù)源全流程

 更新時(shí)間:2022年03月25日 17:10:36   作者:zrk1000  
這篇文章主要介紹了spring注解 @PropertySource配置數(shù)據(jù)源全流程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@PropertySource數(shù)據(jù)源配置

一般在配置數(shù)據(jù)源是都會(huì)使用xml的方式注入,key-value在properties中管理;spring4.X已有著比較完善的注解來替換xml的配置方式。

使用xml配置數(shù)據(jù)源

通常我們使用xml配置數(shù)據(jù)源,使用SpEL獲取properties中的配置。

applicationContext.xml 中配置 dataSource 及 PreferencesPlaceholderConfigurer,使用 PropertyPlaceholderConfigurer進(jìn)行Bean屬性替換

<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
? ? ? ? <property name="locations">
? ? ? ? ? ? <list>
? ? ? ? ? ? ? ? <value>classpath:/jdbc.properties</value>
? ? ? ? ? ? </list>
? ? ? ? </property>
? ? ? ? <property name="fileEncoding" value="utf-8"/>
? ? </bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
? ? <property name="properties" ref="configProperties" />
</bean>
<!-- 使用proxool連接池的數(shù)據(jù)源, -->
<bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
? ? <!-- 數(shù)據(jù)源的別名 -->
? ? <property name="alias" value="${proxool.alias}" />?
? ? <!-- 驅(qū)動(dòng) -->
? ? <property name="driver" value="${proxool.driver}" />?
? ? <!-- 鏈接URL ?-->
? ? <property name="driverUrl" value="${proxool.driverUrl}" />?
? ? <!-- 用戶名-->
? ? <property name="user" value="${proxool.user}" />
? ? <!-- 密碼 -->
? ? <property name="password" value="${proxool.password}" />?
? ? <!-- 最大鏈接數(shù)-->
? ? <property name="maximumConnectionCount" value="${proxool.maximumConnectionCount}" />?
? ? <!-- 最小鏈接數(shù) -->
? ? <property name="minimumConnectionCount" value="${proxool.minimumConnectionCount}" />?
? ? <!-- ...(略) -->
</bean>?

jdbc.properties

proxool.alias=mySql
proxool.driver=com.mysql.jdbc.Driver
proxool.driverUrl=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
proxool.user=root
proxool.password=root
proxool.maximumActiveTime=1200
proxool.maximumConnectionCount=50
#...

使用javaBean配置數(shù)據(jù)源

DataSourceConfiguration類是數(shù)據(jù)源的javaBean配置方式,@Configuratio注解當(dāng)前類,

spring啟動(dòng)時(shí)會(huì)掃描被@Configuratio注解的類,注入當(dāng)前類中配置的方法bean;

當(dāng)然別忘了啟用注解掃描:

<context:annotation-config/> ?
<context:component-scan base-package="com.XXX.test.dateSource"></context:component-scan>

@value注解讀取配置

@value中可以直接使用SpEL,獲取properties配置,成員變量也不需要getter、setter,不過還是有一個(gè)前提,需要配置xml:

<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
? ? ? ? <property name="locations">
? ? ? ? ? ? <list>
? ? ? ? ? ? ? ? <value>classpath:/jdbc.properties</value>
? ? ? ? ? ? </list>
? ? ? ? </property>
? ? ? ? <property name="fileEncoding" value="utf-8"/>
? ? </bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
? ? <property name="properties" ref="configProperties" />
</bean>

@Bean注解:spring掃面當(dāng)前類時(shí),注入每個(gè)有@Bean注解的方法的返回值Bean, name屬性默認(rèn)為返回值類類名首字母小寫,這里自己設(shè)置name。

package com.XXX.test.dateSource;
import org.logicalcobwebs.proxool.ProxoolDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuratio
public class DataSourceConfiguration{
? ? @Value("${proxool.alias}")
? ? private String alias;
? ? @Value("${proxool.driver}")
? ? private String driver;
? ? @Value("${proxool.driverUrl}")
? ? private String driverUrl;
? ? @Value("${proxool.user}")
? ? private String user;
? ? @Value("${proxool.password}")
? ? private String password;
? ? //...
? ? @Bean(name="dataSource")
? ? public ProxoolDataSource dataSource(){
? ? ? ? ?ProxoolDataSource proxoolDataSource = new ProxoolDataSource();
? ? ? ? ?proxoolDataSource.setDriver(driver);
? ? ? ? ?proxoolDataSource.setDriverUrl(driverUrl);
? ? ? ? ?proxoolDataSource.setUser(user);
? ? ? ? ?proxoolDataSource.setPassword(password);
? ? ? ? ?//...
? ? ? ? ?return proxoolDataSource;
? ? ?}
?}

這時(shí)dataSource已被注入,使用時(shí)可注解注入,如下:

? ? @Autowired
? ? private ProxoolDataSource dataSource;

@PropertySource注解讀取配置

@PropertySource注解當(dāng)前類,參數(shù)為對(duì)應(yīng)的配置文件路徑,這種方式加載配置文件,可不用在xml中配置PropertiesFactoryBean引入jdbc.properties,使用時(shí)方便得多,DataSourceConfiguration不再需要成員變量,取而代之的是需要注入一個(gè)Environment環(huán)境配置,使用env.getProperty(key)獲取數(shù)據(jù):

package com.XXX.test.dateSource;
import org.logicalcobwebs.proxool.ProxoolDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
@Configuratio
@PropertySource("classpath:/jdbc.properties")
public class DataSourceConfiguration{
? ? @Autowired
? ? private Environment env;
? ? @Bean(name="dataSource")
? ? public ProxoolDataSource dataSource(){
? ? ? ? ?ProxoolDataSource proxoolDataSource = new ProxoolDataSource();
? ? ? ? ?proxoolDataSource.setDriver(env.getProperty("proxool.alias"));
? ? ? ? ?proxoolDataSource.setDriverUrl(env.getProperty("proxool.driver"));
? ? ? ? ?proxoolDataSource.setUser(env.getProperty("proxool.user"));
? ? ? ? ?proxoolDataSource.setPassword(env.getProperty("proxool.password"));
? ? ? ? ?//...
? ? ? ? ?return proxoolDataSource;
? ? ?}
?}

這里主要是說明注解的用法,所以沒有具體體現(xiàn)數(shù)據(jù)源全部參數(shù)的配置。對(duì)于有強(qiáng)迫癥的來說若項(xiàng)目中所有bean都使用注解,幾乎不太希望僅dataSource用xml類配置,換成類的方式類配置強(qiáng)迫感就消失了! 

注解的spring多數(shù)據(jù)源配置及使用

前一段時(shí)間研究了一下spring多數(shù)據(jù)源的配置和使用,為了后期從多個(gè)數(shù)據(jù)源拉取數(shù)據(jù)定時(shí)進(jìn)行數(shù)據(jù)分析和報(bào)表統(tǒng)計(jì)做準(zhǔn)備。由于之前做過的項(xiàng)目都是單數(shù)據(jù)源的,沒有遇到這種場景,所以也一直沒有去了解過如何配置多數(shù)據(jù)源。

后來發(fā)現(xiàn)其實(shí)基于spring來配置和使用多數(shù)據(jù)源還是比較簡單的,因?yàn)閟pring框架已經(jīng)預(yù)留了這樣的接口可以方便數(shù)據(jù)源的切換。

先看一下spring獲取數(shù)據(jù)源的源碼

可以看到AbstractRoutingDataSource獲取數(shù)據(jù)源之前會(huì)先調(diào)用determineCurrentLookupKey方法查找當(dāng)前的lookupKey,這個(gè)lookupKey就是數(shù)據(jù)源標(biāo)識(shí)。

因此通過重寫這個(gè)查找數(shù)據(jù)源標(biāo)識(shí)的方法就可以讓spring切換到指定的數(shù)據(jù)源了。

第一步:創(chuàng)建一個(gè)DynamicDataSource的類

繼承AbstractRoutingDataSource并重寫determineCurrentLookupKey方法,代碼如下:

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        // 從自定義的位置獲取數(shù)據(jù)源標(biāo)識(shí)
        return DynamicDataSourceHolder.getDataSource();
    }
}

第二步:創(chuàng)建DynamicDataSourceHolder

用于持有當(dāng)前線程中使用的數(shù)據(jù)源標(biāo)識(shí),代碼如下:

public class DynamicDataSourceHolder {
    /**
     * 注意:數(shù)據(jù)源標(biāo)識(shí)保存在線程變量中,避免多線程操作數(shù)據(jù)源時(shí)互相干擾
     */
    private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();
    public static String getDataSource() {
        return THREAD_DATA_SOURCE.get();
    }
    public static void setDataSource(String dataSource) {
        THREAD_DATA_SOURCE.set(dataSource);
    }
    public static void clearDataSource() {
        THREAD_DATA_SOURCE.remove();
    }
}

第三步:配置多個(gè)數(shù)據(jù)源

和第一步里創(chuàng)建的DynamicDataSource的bean,簡化的配置如下:

<!--創(chuàng)建數(shù)據(jù)源1,連接數(shù)據(jù)庫db1 -->
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db1.driver}" />
    <property name="url" value="${db1.url}" />
    <property name="username" value="${db1.username}" />
    <property name="password" value="${db1.password}" />
</bean>
<!--創(chuàng)建數(shù)據(jù)源2,連接數(shù)據(jù)庫db2 -->
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db2.driver}" />
    <property name="url" value="${db2.url}" />
    <property name="username" value="${db2.username}" />
    <property name="password" value="${db2.password}" />
</bean>
<!--創(chuàng)建數(shù)據(jù)源3,連接數(shù)據(jù)庫db3 -->
<bean id="dataSource3" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db3.driver}" />
    <property name="url" value="${db3.url}" />
    <property name="username" value="${db3.username}" />
    <property name="password" value="${db3.password}" />
</bean>
<bean id="dynamicDataSource" class="com.test.context.datasource.DynamicDataSource">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <!-- 指定lookupKey和與之對(duì)應(yīng)的數(shù)據(jù)源 -->
            <entry key="dataSource1" value-ref="dataSource1"></entry>
            <entry key="dataSource2" value-ref="dataSource2"></entry>
            <entry key="dataSource3 " value-ref="dataSource3"></entry>
        </map>
    </property>
    <!-- 這里可以指定默認(rèn)的數(shù)據(jù)源 -->
    <property name="defaultTargetDataSource" ref="dataSource1" />
</bean>

到這里已經(jīng)可以使用多數(shù)據(jù)源了,在操作數(shù)據(jù)庫之前只要DynamicDataSourceHolder.setDataSource("dataSource2")即可切換到數(shù)據(jù)源2并對(duì)數(shù)據(jù)庫db2進(jìn)行操作了。

示例代碼如下:

@Service
public class DataServiceImpl implements DataService {
    @Autowired
    private DataMapper dataMapper;
    @Override
    public List<Map<String, Object>> getList1() {
        // 沒有指定,則默認(rèn)使用數(shù)據(jù)源1
        return dataMapper.getList1();
    }
    @Override
    public List<Map<String, Object>> getList2() {
        // 指定切換到數(shù)據(jù)源2
        DynamicDataSourceHolder.setDataSource("dataSource2");
        return dataMapper.getList2();
    }
    @Override
    public List<Map<String, Object>> getList3() {
        // 指定切換到數(shù)據(jù)源3
        DynamicDataSourceHolder.setDataSource("dataSource3");
        return dataMapper.getList3();
    }
}

----------------------------華麗的分割線----------------------------

但是問題來了,如果每次切換數(shù)據(jù)源時(shí)都調(diào)用DynamicDataSourceHolder.setDataSource("xxx")就顯得十分繁瑣了,而且代碼量大了很容易會(huì)遺漏,后期維護(hù)起來也比較麻煩。能不能直接通過注解的方式指定需要訪問的數(shù)據(jù)源呢,比如在dao層使用@DataSource("xxx")就指定訪問數(shù)據(jù)源xxx?當(dāng)然可以!前提是,再加一點(diǎn)額外的配置^_^。

首先,我們得定義一個(gè)名為DataSource的注解,代碼如下:

@Target({ TYPE, METHOD })
@Retention(RUNTIME)
public @interface DataSource {
    String value();
}

然后,定義AOP切面以便攔截所有帶有注解@DataSource的方法,取出注解的值作為數(shù)據(jù)源標(biāo)識(shí)放到DynamicDataSourceHolder的線程變量中:

public class DataSourceAspect {
    /**
     * 攔截目標(biāo)方法,獲取由@DataSource指定的數(shù)據(jù)源標(biāo)識(shí),設(shè)置到線程存儲(chǔ)中以便切換數(shù)據(jù)源
     *
     * @param point
     * @throws Exception
     */
    public void intercept(JoinPoint point) throws Exception {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 默認(rèn)使用目標(biāo)類型的注解,如果沒有則使用其實(shí)現(xiàn)接口的注解
        for (Class<?> clazz : target.getInterfaces()) {
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());
    }
    /**
     * 提取目標(biāo)對(duì)象方法注解和類型注解中的數(shù)據(jù)源標(biāo)識(shí)
     *
     * @param clazz
     * @param method
     */
    private void resolveDataSource(Class<?> clazz, Method method) {
        try {
            Class<?>[] types = method.getParameterTypes();
            // 默認(rèn)使用類型注解
            if (clazz.isAnnotationPresent(DataSource.class)) {
                DataSource source = clazz.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.value());
            }
            // 方法注解可以覆蓋類型注解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.value());
            }
        } catch (Exception e) {
            System.out.println(clazz + ":" + e.getMessage());
        }
    }
}

最后在spring配置文件中配置攔截規(guī)則就可以了,比如攔截service層或者dao層的所有方法:

<bean id="dataSourceAspect" class="com.test.context.datasource.DataSourceAspect" />
    <aop:config>
        <aop:aspect ref="dataSourceAspect">
            <!-- 攔截所有service方法 -->
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.test.*.dao.*.*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
        </aop:aspect>
    </aop:config>
</bean>

OK,這樣就可以直接在類或者方法上使用注解@DataSource來指定數(shù)據(jù)源,不需要每次都手動(dòng)設(shè)置了。

示例代碼如下:

@Service
// 默認(rèn)DataServiceImpl下的所有方法均訪問數(shù)據(jù)源1
@DataSource("dataSource1")
public class DataServiceImpl implements DataService {
    @Autowired
    private DataMapper dataMapper;
    @Override
    public List<Map<String, Object>> getList1() {
        // 不指定,則默認(rèn)使用數(shù)據(jù)源1
        return dataMapper.getList1();
    }
    @Override
    // 覆蓋類上指定的,使用數(shù)據(jù)源2
    @DataSource("dataSource2")
    public List<Map<String, Object>> getList2() {
        return dataMapper.getList2();
    }
    @Override
    // 覆蓋類上指定的,使用數(shù)據(jù)源3
    @DataSource("dataSource3")
    public List<Map<String, Object>> getList3() {
        return dataMapper.getList3();
    }
}

提示:注解@DataSource既可以加在方法上,也可以加在接口或者接口的實(shí)現(xiàn)類上,優(yōu)先級(jí)別:方法>實(shí)現(xiàn)類>接口。也就是說如果接口、接口實(shí)現(xiàn)類以及方法上分別加了@DataSource注解來指定數(shù)據(jù)源,則優(yōu)先以方法上指定的為準(zhǔn)。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spark學(xué)習(xí)筆記 (二)Spark2.3 HA集群的分布式安裝圖文詳解

    Spark學(xué)習(xí)筆記 (二)Spark2.3 HA集群的分布式安裝圖文詳解

    這篇文章主要介紹了Spark2.3 HA集群的分布式安裝,結(jié)合圖文與實(shí)例形式詳細(xì)分析了Spark2.3 HA集群分布式安裝具體下載、安裝、配置、啟動(dòng)及執(zhí)行spark程序等相關(guān)操作技巧,需要的朋友可以參考下
    2020-02-02
  • Java遞歸算法的使用分析

    Java遞歸算法的使用分析

    本篇文章介紹了,在Java中遞歸算法的使用分析。需要的朋友參考下
    2013-04-04
  • 關(guān)于Java中重定向傳參與取值

    關(guān)于Java中重定向傳參與取值

    這篇文章主要介紹了Java中重定向傳參與取值問題,重定向不僅可以重定向到當(dāng)前應(yīng)用程序中的其他資源,還可以重定向到同一個(gè)站點(diǎn)上的其他應(yīng)用程序中的資源,甚至是使用絕對(duì)URL重定向到其他站點(diǎn)的資源,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • 使用java操作elasticsearch的具體方法

    使用java操作elasticsearch的具體方法

    本篇文章主要介紹了使用java操作elasticsearch的具體方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java多線程之ReentrantReadWriteLock源碼解析

    Java多線程之ReentrantReadWriteLock源碼解析

    這篇文章主要介紹了Java多線程之ReentrantReadWriteLock源碼解析,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • Java中super關(guān)鍵字介紹以及super()的使用

    Java中super關(guān)鍵字介紹以及super()的使用

    這幾天看到類在繼承時(shí)會(huì)用到this和super,這里就做了一點(diǎn)總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中super關(guān)鍵字介紹以及super()使用的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • JDBC連接數(shù)據(jù)庫步驟及基本操作示例詳解

    JDBC連接數(shù)據(jù)庫步驟及基本操作示例詳解

    這篇文章主要為大家介紹了JDBC連接數(shù)據(jù)庫步驟及基本操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java數(shù)據(jù)結(jié)構(gòu)之有向圖設(shè)計(jì)與實(shí)現(xiàn)詳解

    Java數(shù)據(jù)結(jié)構(gòu)之有向圖設(shè)計(jì)與實(shí)現(xiàn)詳解

    有向圖是具有方向性的圖,由一組頂點(diǎn)和一組有方向的邊組成,每條方向的邊都連著一對(duì)有序的頂點(diǎn)。本文為大家介紹的是有向圖的設(shè)計(jì)與實(shí)現(xiàn),需要的可以參考一下
    2022-11-11
  • Java生成訂單號(hào)或唯一id的高并發(fā)方案(4種方法)

    Java生成訂單號(hào)或唯一id的高并發(fā)方案(4種方法)

    本文主要介紹了Java生成訂單號(hào)或唯一id的高并發(fā)方案,包括4種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • JAVA獲取rabbitmq消息總數(shù)過程詳解

    JAVA獲取rabbitmq消息總數(shù)過程詳解

    這篇文章主要介紹了JAVA獲取rabbitmq消息總數(shù)過程詳解,公司使用的是rabbitMQ,需要做監(jiān)控預(yù)警的job去監(jiān)控rabbitMQ里面的堆積消息個(gè)數(shù),如何使用rabbitMQ獲取監(jiān)控的隊(duì)列里面的隊(duì)列消息個(gè)數(shù)呢,需要的朋友可以參考下
    2019-07-07

最新評(píng)論