怎樣做才是最優雅方式切換 Web 專案資料來源 ?

來源:互聯網
上載者:User

標籤:lan   eth   pool   .net   ted   ram   方案   name   info   

   隨著業務變遷/需求變更,JavaEE 應用中會被迫串連多個資料來源進行業務處理。

   怎樣在不影響原有項目結構的情況下,已最優雅/最簡潔的方式動態切換資料來源呢?

   本文已一次添加資料來源後動態切換實踐為例,描述整個思考和實踐過程,文中如有紕漏,還望指正。

1. 依賴 Spring  動態資料源實現

   

   Spring 中提供了一個叫做 AbstractRoutingDataSource 抽象路由資料來源對象繼承自 AbstractDataSource 並實現了 JDK 中 DataSource 介面。

   也就意味著繼承 AbstractRoutingDataSource  並重寫它 determineCurrentLookupKey 方法的類可以作為資料來源,並個人化多資料來源動態路由切換。

   (如果你平時夠仔細的話,現開源的資料庫連接池都實現 DataSource 介面並進行了自己的個人化封裝。)

public class DynamicDataSource extends AbstractRoutingDataSource {    @Override    protected Object determineCurrentLookupKey() {        return DbContextHolder.getDbType();    }}

   對於一次 web 請求來說可以理解為單獨的線程,將當前資料來源暫存線上程當中是比較合理的做法。

public class DbContextHolder {    private static final ThreadLocal contextHolder = new ThreadLocal<>();    /**     * 設定資料來源     *     * @param dbSourceEnum 要設定的資料庫枚舉名稱     */    public static void setDbType(DBSourceEnum dbSourceEnum) {        contextHolder.set(dbSourceEnum.getValue());    }    /**     * 取得當前資料來源     */    public static String getDbType() {        return String.valueOf(contextHolder.get());    }    /**     * 清除上下文資料     */    public static void clearDbType() {        contextHolder.remove();    }}

   當然為了後期的擴充和維護,以及使用的便捷性,這裡資料來源對象我們引入枚舉類型。

   這樣後續其他同事編程使用枚舉,改動起來也相當方便,還能進行二次資料來源的一些自訂標示。

public enum DBSourceEnum {    one("dataSource1"),    two("dataSource2");    private String value;    DBSourceEnum(String value) {        this.value = value;    }    public String getValue() {        return value;    }}

   上述的 dataSource1/dataSource2 即為 spring-context  中已載入的資料來源對象 Id。

    <bean name="dataSource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">        ......    </bean>
    <bean name="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">        ......    </bean>

   接下來在 context 中設定繼承自 AbstractRoutingDataSource 的 DynamicDataSource。

   <bean id="dataSource" class="com.rambo.spm.core.multidb.DynamicDataSource">        <property name="targetDataSources">            <map key-type="java.lang.String">                <entry key="dataSource1" value-ref="dataSource1"/>                <entry key="dataSource2" value-ref="dataSource2"/>            </map>        </property>        <property name="defaultTargetDataSource" ref="dataSource1"/>    </bean>

   Ok,這樣在配置後續 dao 層時使用該 DynamicDataSource 即可。

2. 最優雅的切換資料來源方式

   完成上述工作之後,其實動態切換資料來源對象已經時可以起作用了,在業務層如下面這樣編程。

        DbContextHolder.setDbType(DBSourceEnum.one);        List<Menu> menuList = menuService.selectList(null);        DbContextHolder.setDbType(DBSourceEnum.two);        List<User> userList = userService.selectList(null);

   缺點很明顯,串連資料來源2時要進行切換/不利於擴充/切換不當時給後人埋雷的幾率很大。

   和團隊進行交流時,討論出用強大 aop 來攔截 dao 層對象,動態切換資料來源的方案。

   對於 dao 層對象來說訪問那個資料庫的哪張表是確定的,編寫自訂註解,與 dao 層對象進行綁定。

   自訂資料來源註解如下:

@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface DataSource {    DBSourceEnum value() default DBSourceEnum.one;}

   編寫切面處理對象,在 dao 層對象使用前進行攔截,順手切換資料來源,如果沒有資料來源註解,設定為預設。

   所以對於原項目中第一個資料來源 dao 層對象,不需要進行任何修改,切面處理如下。

    @Before("cut()")    public void doBefore(JoinPoint joinPoint) {        DataSource dataSource = joinPoint.getTarget().getClass().getAnnotation(DataSource.class);        DbContextHolder.setDbType(dataSource != null ? dataSource.value() : DBSourceEnum.one);        log.info("當前資料來源為:" + DbContextHolder.getDbType());    }

   多數項目中 dao 層錯綜複雜的抽象和繼承關係會給你 aop 切面攔截造成一定的困難,多思考、多實踐總會有辦法的。

   好了,就這樣吧,是不是感覺比 aop 攔截方式比在程式中寫入程式碼更容易擴充、更容易編程、更容易理解,當然也更優雅。

   代碼已託管在:https://git.oschina.net/LanboEx/spmvc-mybatis.git 有興趣的朋友,可以檢到本地 run 一下。

  

怎樣做才是最優雅方式切換 Web 專案資料來源 ?

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.