當前位置:
首頁 > 知識 > Spring Boot 聲明式事務結合相關攔截器

Spring Boot 聲明式事務結合相關攔截器

我這項目的讀寫分離方式在使用ThreadLocal實現的讀寫分離在遷移後的偶發錯誤里提了,我不再說一次了,這次是有要求讀寫分離與事務部分要完全脫離配置文件,程序員折騰了很久,於是我就查了一下,由於我還是比較喜歡使用xml的方式,所以就隨便。。。(過程省略吧),然而,似乎是一定要聲明式的方式,所以,無奈之下就只好乾了。

首先,在之前的博客里提到過,我們的讀寫分離方式要求我們自己的AOP攔截器必須在事務攔截器之前執行,在配置文件的方式下很容易,在aop的配置里設置一下Order就好了。然而,Spring Boot的@EnableTransactionManagement註解中已經把這部分固定了,官方文檔似乎說它是和@Transactional配合使用的,總之幾乎沒有留下什麼插手的餘地(如果大家有好辦法,希望能告訴我一下):

Spring Boot 聲明式事務結合相關攔截器

public TransactionInterceptor transactionInterceptor {
TransactionInterceptor interceptor = new TransactionInterceptor;
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}

雖然這裡可以通過上圖的方式加點什麼,但這個事務體系本身是非常獨立的,而且在啟動過程中就已經確定下來了,既然要調節它和自定義的aop的執行順序,我想只能先統一他們的執行策略。之前自定義的aop是在啟動過程中就被加入到一個攔截器的調用鏈中:

Spring Boot 聲明式事務結合相關攔截器

由於Spring Boot很多東西並沒有留什麼擴展的餘地(就好像前面那個new),如果完全不用配置文件,使用Spring Boot的方式,雖然沒有什麼順眼的方法,其實也還是能做的,先提個建議,能不用的情況下,最好不要用。方法是自定義一個事務攔截器,拋棄@EnableTransactionManagement,測試代碼如下,不要在意命名,圖方便直接在原來的上面改的:

@Bean(name = "newDataSourceAop")
public NewDataSourceAop newDataSourceAop{
return new NewDataSourceAop;
}

@Bean(name = "tInterceptor")
public TInterceptor tInterceptor{
return new TInterceptor;
}

/**
* 代理
* @return
*/
@Bean
public BeanNameAutoProxyCreator transactionAutoProxy {
BeanNameAutoProxyCreator autoProxy = new BeanNameAutoProxyCreator;
autoProxy.setProxyTargetClass(true);// 這個屬性為true時,表示被代理的是目標類本身而不是目標類的介面
autoProxy.setBeanNames("*ServiceImpl");
autoProxy.setInterceptorNames("newDataSourceAop", "tInterceptor");
return autoProxy;
}

注意,攔截器的順序依賴於名字字元串傳入的先後順序,@Order什麼的是完全沒用的,因為保存這些攔截器的是一個字元串數組。自定義的事務AOP Advice:

public class TInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

public TInterceptor {
setTransactionAttributes(getAttrs);
}

private Properties getAttrs{
Properties attributes = new Properties;
// 新增
attributes.setProperty("create*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
// 修改
attributes.setProperty("update*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
// 刪除
attributes.setProperty("delete*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
//查詢
attributes.setProperty("query*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
return attributes;
}

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Class targetClass = (invocation.getThis != null ? AopUtils.getTargetClass(invocation.getThis) : null);

// Adapt to TransactionAspectSupport"s invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod, targetClass, -> invocation.proceed);
}
}

自定義的讀寫分離Advice:

@EnableConfigurationProperties(ReadDBPathProperties.class)
public class NewDataSourceAop implements MethodBeforeAdvice {
private static final Logger log = LoggerFactory.getLogger(NewDataSourceAop.class);

@Autowired
private ReadDBPathProperties readDBPathProperties;

@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String clazzName = method.getDeclaringClass.getSimpleName;
String runner = clazzName + "." + method.getName;
this.chooseDataSource(runner);
}

private void chooseDataSource(String runner){
runner += ",";
String read = readDBPathProperties.getReadPath+",";
log.info("case : read path, vo : readPath = {}", read);
int index = read.indexOf(runner);
if (index == -1){
log.info("case : choose write DB, runner : {}, tid={}", runner, Thread.currentThread.getId);
HandleDataSource.putDataSource("write");
return;
}
log.info("case : choose read DB, runner : {}, tid={}", runner, Thread.currentThread.getId);
HandleDataSource.putDataSource("read");
}
}

最後再特別說一下,關於這個功能的單元測試,這個單元測試有一點意思,如果是直接運行測試方法,啟動過程和執行過程在同一個線程是測試不出效果的,因為啟動過程中載入Bean的時候會對下圖中的resources初始化,寫入默認的數據源:

就會導致後續執行的讀寫分離攔截器失效,只要保證執行線程和啟動線程不在同一線程就好。

==========================================================

咱最近用的github:https://github.com/saaavsaaa

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 達人科技 的精彩文章:

收集的常用簡單的演算法
springcloud(七):配置中心svn示例和refresh
Neo4j 第四篇:使用C更新和查詢Neo4j
mui.openWindow+自定義事件監聽操作讓alert()執行兩次

TAG:達人科技 |

您可能感興趣

「與iOS裝置完美結合」Beats Powerbeats Pro運動用真藍牙耳機
阿甘鞋與Vapor Street結合!Nike Moon Racer 登場!
Cobbler與Django結合
ActiveMQ 結合 Spring 收發
科技與機能的結合!Nike Air Presto mid x Acron
新品丨「與iOS裝置完美結合」Beats Powerbeats Pro運動用真藍牙耳機
ClickHouse如何結合自家的GNDT演算法庫CatBoost來做機器學習
科技與經典完美結合,adidas Originals Arkyn現已魅力登場
如果 Nike 和 Balenciaga 結合會是什麼樣?
復古與現代的結合!Bristol Studio x adidas Crazy BYW 入手難度不小!
黑紅與芝加哥的結合,Air Jordan 1「Homage to Home」
復古與現代的結合!Bristol Studio x adidas Crazy BYW 入手難度不小!
Gradle Plugin Portal:結合點擊劫持和CSRF漏洞實現帳戶接管
Nike x Balenciaga聯名?Triple S結合VaporMax要逆天?
Flink與Spark Streaming在與kafka結合的區別!
想結合日常生活對小朋友進行英語教學?試試這套《Talk To Your Child In English》
數控加工結合3D列印,看看Materialize與HCL Technologies碰出什麼火花
Logo與指紋結合 moto G6 play真機曝光
真不怕熱!Nike Air Foamposite one將牛仔布和水晶底結合!
FPGA與ASIC的完美結合,Achronix Speedster 7t系列詳解