簡體   English   中英

使用Java手動創建帶有@Transactional方法的Spring @Service實例

[英]Create Spring @Service instance with @Transactional methods manually from Java

假設有@Service@Repository接口,如下所示:

@Repository
public interface OrderDao extends JpaRepository<Order, Integer> {

}

public interface OrderService {

    void saveOrder(Order order);

}

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;

    @Override
    @Transactional
    public void saveOrder(Order order) {
        orderDao.save(order);
    }

}

這是工作應用程序的一部分,一切都配置為訪問單個數據庫,一切正常。

現在,我希望有可能使用純JavaJava代碼中指定的 jdbcUrl自動連接OrderDao創建OrderService的獨立工作實例 ,如下所示:

final int tenantId = 3578;
final String jdbcUrl = "jdbc:mysql://localhost:3306/database_" + tenantId;
OrderService orderService = someMethodWithSpringMagic(appContext, jdbcUrl);

正如您所看到的,我想向現有的基於Spring的應用程序引入具有每個數據庫策略租戶的 多租戶架構

請注意,在使用自己實現的類似jdbcTemplate的邏輯之前,我能夠很容易地實現這一點,並且JDBC事務正確地工作,因此這是非常有效的任務

還請注意,我需要非常簡單的事務邏輯來啟動事務,在該事務范圍內的service方法中執行多個請求,然后在異常時提交/回滾。

Web上關於多租戶的大多數解決方案都建議在xml配置和/或使用基於注釋的配置中指定具體的持久性單元,這是非常不靈活的,因為為了添加新的數據庫url應該停止整個應用程序,xml config / annotation code應該更改並啟動應用程序。

所以,基本上我正在尋找一段能夠創建@Service的代碼,就像Spring在從XML配置/注釋中讀取屬性后在內部創建它一樣。 我也在考慮使用ProxyBeanFactory ,因為Spring使用AOP來創建服務實例(所以我想簡單的舊的可重用OOP不是這里的方法)。

Spring是否足夠靈活 ,允許這種相對簡單的代碼重用案例

任何提示將不勝感激 ,如果我找到這個問題的完整答案,我會在這里發布給后代:)

為帶注釋的服務創建事務代理並不是一項艱巨的任務,但我不確定您是否確實需要它。 為tenantId選擇一個數據庫我想你只需要專注於DataSource接口。

例如,使用簡單的驅動程序托管數據源:

public class MultitenancyDriverManagerDataSource extends DriverManagerDataSource {

    @Override
    protected Connection getConnectionFromDriverManager(String url,
            Properties props) throws SQLException {

        Integer tenant = MultitenancyContext.getTenantId();

        if (tenant != null)
            url += "_" + tenant;

        return super.getConnectionFromDriverManager(url, props);
    }

}

public class MultitenancyContext {

    private static ThreadLocal<Integer> tenant = new ThreadLocal<Integer>();

    public static Integer getTenantId() {
        return tenant.get();
    }

    public static void setTenatId(Integer value) {
        tenant.set(value);
    }
}

當然,如果要使用連接池,則需要對其進行詳細說明,例如每個租戶使用一個連接池。

HIbernate 對多租戶提供開箱即用的支持,在嘗試自己之前先檢查一下。 Hibernate需要一個MultiTenantConnectionProviderCurrentTenantIdentifierResolver ,其默認實現開箱即用,但您始終可以編寫自己的實現。 如果它只是一個模式更改,實際上很容易實現(在返回連接之前執行查詢)。 否則,保存數據源地圖並從中獲取實例,或創建新實例。

大約8年前,我們已經編寫了一個通用解決方案, 此處已記錄在案,代碼就在這里 它不是特定於休眠的,並且可以與基本上需要切換的任何東西一起使用。 我們將它用於DataSource以及一些與Web相關的東西(其中包括其他內容)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM