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

任何Bean通過實(shí)現(xiàn)ProxyableBeanAccessor接口即可獲得動(dòng)態(tài)靈活的獲取代理對(duì)象或原生對(duì)象的能力(最新推薦)

 更新時(shí)間:2024年02月04日 09:35:22   作者:夢(mèng)在旅途  
這篇文章主要介紹了任何Bean通過實(shí)現(xiàn)ProxyableBeanAccessor接口即可獲得動(dòng)態(tài)靈活的獲取代理對(duì)象或原生對(duì)象的能力,通過示例代碼看到,借助ProxyableBeanAccessor接口默認(rèn)實(shí)現(xiàn)的getReal、getProxy、selfAs方法,很靈活的按需獲取代理或非代理對(duì)象,需要的朋友可以參考下

如果一個(gè)BEAN類上加了@Transactional,則默認(rèn)的該類及其子類的公開方法均會(huì)開啟事務(wù),但有時(shí)某些業(yè)務(wù)場(chǎng)景下某些公開的方法可能并不需要事務(wù),那這種情況該如何做呢?

常規(guī)的做法:

針對(duì)不同的場(chǎng)景及事務(wù)傳播特性,定義不同的公開方法【哪怕是同一種業(yè)務(wù)】,并在方法上添加@Transactional且指明不同的傳播特性,示例代碼如下:

@Service
@Transactional
public class DemoSerivce {
   //SUPPORTED 若無(wú)事務(wù)傳播則默認(rèn)不會(huì)有事務(wù),若有事務(wù)傳播則會(huì)開啟事務(wù)
   @Transactional(propagation = Propagation.SUPPORTED)
   public int getValue(){
      return 0;
   }
   //默認(rèn)開啟事務(wù)(由類上的@Transactional決定的)
   public int getValueWithTx(){
      return 0;
   }
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
   public int getValueWithoutTx(){
      return 0;
   }
}

上述這樣的弊端就是:若是同一個(gè)邏輯但如果要精細(xì)控制事務(wù),則需要定義3個(gè)方法來(lái)支持,getValue、getValueWithTx、getValueWithoutTx 3個(gè)方法,分別對(duì)應(yīng)3種事務(wù)場(chǎng)景,這種代碼就顯得冗余過多,那有沒有簡(jiǎn)單一點(diǎn)的方案呢?其實(shí)是有的。

聲明式事務(wù)的本質(zhì)是通過AOP切面,在代理執(zhí)行原始方法【即:被標(biāo)注了@Transactional的公開方法】前開啟DB事務(wù),在執(zhí)行后提交DB事務(wù)(若拋錯(cuò)則執(zhí)行回滾),如果要想事務(wù)不生效,則讓AOP失效即可,即:調(diào)原生的service Bean公開方法而不是代理類的公開方法,那如何獲得原生的BEAN類呢,答案是:在原生BEAN方法內(nèi)部通過this獲取即可,如果沒理解,下面寫一個(gè)手寫代理示例,大家就明白了:

public class DemoService{
    public int getValue(){
        return 666;
    }
    public DemoService getReal(){
        //這里的this指向的就是當(dāng)前的自己,并非代理對(duì)象
        return this;
    }
}
public class DemoServiceProxy{
    private DemoService target;
    public DemoServiceProxy(DemoService target){
        this.target=target;
    }
    public int getValue(){
        //增強(qiáng):開啟事務(wù)
        return  target.getValue()+222;
        //增強(qiáng):提交事務(wù)
    }
    public DemoService getReal(){
        //這里就會(huì)間接的把原生的對(duì)象傳遞返回
        return target.getReal();
    }
}
    public static void main(String[] args) {
        DemoServiceProxy proxy=new DemoServiceProxy(new DemoService());
        System.out.println("proxy class:" +proxy.getClass().getName());
        System.out.println("real class:" +proxy.getReal().getClass().getName());
        System.out.println("proxy getValue result:" + proxy.getValue() );
        System.out.println("real getValue result:" + proxy.getReal().getValue() );
    }

最終的輸出結(jié)果為:

proxy class:...DemoServiceProxy
real class:...DemoService →原始的對(duì)象

proxy getValue result:888
real getValue result:666

通過DEMO證實(shí)了通過避開代理的方案是正確的,而且非常簡(jiǎn)單,那么有了這個(gè)基礎(chǔ),再應(yīng)用到實(shí)際的代碼中則很簡(jiǎn)單,想控制有事務(wù)則取代理對(duì)象,想控制不要事務(wù)則取原生對(duì)象即可,就是這么簡(jiǎn)單。

下面貼出核心也是全部的ProxyableBeanAccessor代碼:(注意必需擴(kuò)展自RawTargetAccess,否則即使返回this也會(huì)被強(qiáng)制返回代理)

/**
 * @author zuowenjun
 * @date 2022/12/5 22:03
 * @description 可代理BEAN訪問者接口(支持獲取代理的真實(shí)對(duì)象、獲取代理對(duì)象)
 */
public interface ProxyableBeanAccessor<T extends ProxyableBeanAccessor> extends RawTargetAccess {
    String CONTEXT_KEY_REAL_GET = "proxyable_bean_accessor_real_get";
    /**
     * 獲取代理的真實(shí)對(duì)象(即:未被代理的對(duì)象)
     * 注:若調(diào)用未被代理的bean的公開方法,則均不會(huì)再走AOP切面
     *
     * @return 未被代理的對(duì)象Bean
     */
    @SuppressWarnings("unchecked")
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    default T getReal() {
        return (T) this;
    }
    /**
     * 獲取當(dāng)前類的代理對(duì)象(即:已被代理的對(duì)象)
     * 注:若調(diào)用已被代理的對(duì)象Bean的公開方法,則相關(guān)AOP切面均可正常攔截與執(zhí)行
     *
     * @return 已被代理的對(duì)象Bean
     */
    @SuppressWarnings("unchecked")
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    default T getProxy() {
        return (T) SpringUtils.getBean(this.getClass());
    }
    /**
     * 將當(dāng)前BEAN轉(zhuǎn)換為代理對(duì)象或真實(shí)對(duì)象
     *
     * @param realGet 是否轉(zhuǎn)換獲取真實(shí)對(duì)象
     * @return 未被代理的對(duì)象Bean OR 已被代理的對(duì)象Bean
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    default T selfAs(Supplier<Boolean> realGet) {
        Boolean needGetReal = false;
        if (realGet == null) {
            if (ContextUtils.get() != null) {
                needGetReal = (Boolean) ContextUtils.get().getGlobalVariableMap().getOrDefault(CONTEXT_KEY_REAL_GET, false);
            }
        } else {
            needGetReal = realGet.get();
        }
        return Boolean.TRUE.equals(needGetReal) ? getReal() : getProxy();
    }
}

其中,SpringUtils是一個(gè)獲取BEAN的工具類,代碼如下:

public SpringUtils implements ApplicationContextAware{
private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        context=applicationContext;
    }
  public static <T> getBean(Class<T> clazz){
     return context.getBean(clazz);
   }
}

ContextUtils只是一個(gè)內(nèi)部定義了一個(gè)ThreadLocal的靜態(tài)map字段,用于存放線程上下文要傳遞的對(duì)象。

使用方法:只需將原來(lái)Service的子類或其它可能被切面代理的類 加上實(shí)現(xiàn)自ProxyableBeanAccessor即可,然后在這個(gè)類里面或外部調(diào)用均可通過getReal獲得原生對(duì)象、getProxy獲得代理對(duì)象、selfAs動(dòng)態(tài)根據(jù)條件來(lái)判斷是否需要代理或原生對(duì)象,使用示例如下:

//serive BEAN定義
@Service
@Transactional
public class DemoService implements ProxyableBeanAccessor<DemoService> {
   ... ...
    public Demo selectByMergerParam(Demo demo){
       return getMapper().selectByMergerParam(demo);
    }
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Demo selectByMergerParam2(Demo demo){
        //通過getProxy獲取當(dāng)前類的代理BEAN,以便可以執(zhí)行事務(wù)切面
        return getProxy().doSelectByMergerParam(demo);
    }
    public Demo doSelectByMergerParam(Demo demo){
        return getMapper().selectByMergerParam(demo);
    }
}
//具體使用:
    @Autowired
    private DemoService demoService;
            Demo query = new Demo ();
            query.setWaybillNumber("123455667");
            //示例一:獲取原生對(duì)象查詢,由于沒有代理,則無(wú)事務(wù)
            demoService.getReal().selectByMergerParam(query);
            //示例二:根據(jù)LAMBDA表達(dá)式的布爾值來(lái)決定是否獲取原生或代理(這里演示:如果是TIDB,則獲取原生對(duì)象,即:不開事務(wù))
            demoService.selfAs(()-> TidbDataSourceSwitcher.isUsingTidbDataSource()).selectByMergerParam(query);
            //示例三:根據(jù)線程上下文設(shè)置的布爾值來(lái)決定是否獲取原生或代理(這里演示:如果是TIDB,則獲取原生對(duì)象,即:不開事務(wù)),這種方式主要是為了簡(jiǎn)化大批量的動(dòng)態(tài)邏輯判斷的場(chǎng)景,
            // 一次設(shè)置同線程的所有ProxyableBeanAccessor的子類的selfAs(null)均可自動(dòng)判斷
            ContextUtils.get().addGlobalVariable(ProxyableBeanAccessor.CONTEXT_KEY_REAL_GET,TidbDataSourceSwitcher.isUsingTidbDataSource());
            demoService.selfAs(null).selectByMergerParam(query);
            //示例四:獲取代理對(duì)象,一般用于BEAN內(nèi)部方法之間調(diào)用,外部調(diào)用其實(shí)本身就是代理無(wú)意義
            demoService.getProxy().selectByMergerParam(query);

通過上述示例代碼可以看到,借助于ProxyableBeanAccessor接口默認(rèn)實(shí)現(xiàn)的getReal、getProxy、selfAs方法,可以很靈活的實(shí)現(xiàn)按需獲取代理或非代理對(duì)象。

到此這篇關(guān)于任何Bean通過實(shí)現(xiàn)ProxyableBeanAccessor接口即可獲得動(dòng)態(tài)靈活的獲取代理對(duì)象或原生對(duì)象的能力 的文章就介紹到這了,更多相關(guān)Bean ProxyableBeanAccessor接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring-data-redis 2.0 的使用示例代碼

    spring-data-redis 2.0 的使用示例代碼

    這篇文章主要介紹了spring-data-redis 2.0 的使用示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • Springboot實(shí)現(xiàn)ModbusTCP通信的示例詳解

    Springboot實(shí)現(xiàn)ModbusTCP通信的示例詳解

    ModbusTCP協(xié)議是Modbus由MODICON公司于1979年開發(fā),是一種工業(yè)現(xiàn)場(chǎng)總線協(xié)議標(biāo)準(zhǔn),本文主要介紹了Springboot實(shí)現(xiàn)ModbusTCP通信的相關(guān)知識(shí),需要的可以參考下
    2023-12-12
  • Java之SpringBoot自定義配置與整合Druid

    Java之SpringBoot自定義配置與整合Druid

    這篇文章主要介紹的是java之SpringBoot自定義配置與整合Druid的相關(guān)資料,關(guān)于SpringBoot配置文件可以是properties或者是yaml格式的文件,但是在SpringBoot加載application配置文件時(shí)是存在一個(gè)優(yōu)先級(jí),下面小編就和大家一起進(jìn)入文章學(xué)習(xí)這項(xiàng)知識(shí)
    2021-09-09
  • Java實(shí)現(xiàn)在不同線程中運(yùn)行的代碼實(shí)例

    Java實(shí)現(xiàn)在不同線程中運(yùn)行的代碼實(shí)例

    這篇文章主要介紹了Java實(shí)現(xiàn)在不同線程中運(yùn)行的代碼,結(jié)合具體實(shí)例形式分析了java多線程操作的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-04-04
  • Springboot?yml?Map?List讀取方式

    Springboot?yml?Map?List讀取方式

    這篇文章主要介紹了Springboot?yml?Map?List讀取方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java詳解IO流創(chuàng)建讀取與寫入操作

    Java詳解IO流創(chuàng)建讀取與寫入操作

    這篇文章主要介紹了Java IO流,同時(shí)也介紹了流中的一些相關(guān)的內(nèi)容,并且通過大量的案例供大家理解。最后通過一些經(jīng)典的案例幫助大家對(duì)前面所學(xué)的知識(shí)做了一個(gè)綜合的應(yīng)用,需要的朋友可以參考一下
    2022-05-05
  • Java?easyExcel的復(fù)雜表頭多級(jí)表頭導(dǎo)入

    Java?easyExcel的復(fù)雜表頭多級(jí)表頭導(dǎo)入

    最近在項(xiàng)目開發(fā)中遇到的一個(gè)excel復(fù)雜表頭的導(dǎo)入數(shù)據(jù)庫(kù)操作,下面這篇文章主要給大家介紹了關(guān)于Java?easyExcel的復(fù)雜表頭多級(jí)表頭導(dǎo)入的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作實(shí)例代碼

    Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Scala異常處理的方法深入分析

    Scala異常處理的方法深入分析

    Scala是一種多范式的編程語(yǔ)言,支持面向?qū)ο蠛秃瘮?shù)式編程。Scala也支持異常處理,即在程序運(yùn)行過程中發(fā)生意外或錯(cuò)誤時(shí),采取相應(yīng)的措施
    2023-04-04
  • Java異常處理及自定義異常詳細(xì)指南

    Java異常處理及自定義異常詳細(xì)指南

    異常處理是Java編程中的一個(gè)重要部分,用于處理程序執(zhí)行中出現(xiàn)的異常情況,此外還可以自定義異常來(lái)處理特定的錯(cuò)誤情況,掌握這些異常處理技術(shù)對(duì)于編寫健壯、可靠的Java程序至關(guān)重要,需要的朋友可以參考下
    2024-10-10

最新評(píng)論