最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

常規(guī)的做法:

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

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

上述這樣的弊端就是:若是同一個邏輯但如果要精細控制事務,則需要定義3個方法來支持,getValue、getValueWithTx、getValueWithoutTx 3個方法,分別對應3種事務場景,這種代碼就顯得冗余過多,那有沒有簡單一點的方案呢?其實是有的。

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

public class DemoService{
    public int getValue(){
        return 666;
    }
    public DemoService getReal(){
        //這里的this指向的就是當前的自己,并非代理對象
        return this;
    }
}
public class DemoServiceProxy{
    private DemoService target;
    public DemoServiceProxy(DemoService target){
        this.target=target;
    }
    public int getValue(){
        //增強:開啟事務
        return  target.getValue()+222;
        //增強:提交事務
    }
    public DemoService getReal(){
        //這里就會間接的把原生的對象傳遞返回
        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() );
    }

最終的輸出結果為:

proxy class:...DemoServiceProxy
real class:...DemoService →原始的對象

proxy getValue result:888
real getValue result:666

通過DEMO證實了通過避開代理的方案是正確的,而且非常簡單,那么有了這個基礎,再應用到實際的代碼中則很簡單,想控制有事務則取代理對象,想控制不要事務則取原生對象即可,就是這么簡單。

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

/**
 * @author zuowenjun
 * @date 2022/12/5 22:03
 * @description 可代理BEAN訪問者接口(支持獲取代理的真實對象、獲取代理對象)
 */
public interface ProxyableBeanAccessor<T extends ProxyableBeanAccessor> extends RawTargetAccess {
    String CONTEXT_KEY_REAL_GET = "proxyable_bean_accessor_real_get";
    /**
     * 獲取代理的真實對象(即:未被代理的對象)
     * 注:若調(diào)用未被代理的bean的公開方法,則均不會再走AOP切面
     *
     * @return 未被代理的對象Bean
     */
    @SuppressWarnings("unchecked")
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    default T getReal() {
        return (T) this;
    }
    /**
     * 獲取當前類的代理對象(即:已被代理的對象)
     * 注:若調(diào)用已被代理的對象Bean的公開方法,則相關AOP切面均可正常攔截與執(zhí)行
     *
     * @return 已被代理的對象Bean
     */
    @SuppressWarnings("unchecked")
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    default T getProxy() {
        return (T) SpringUtils.getBean(this.getClass());
    }
    /**
     * 將當前BEAN轉(zhuǎn)換為代理對象或真實對象
     *
     * @param realGet 是否轉(zhuǎn)換獲取真實對象
     * @return 未被代理的對象Bean OR 已被代理的對象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是一個獲取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只是一個內(nèi)部定義了一個ThreadLocal的靜態(tài)map字段,用于存放線程上下文要傳遞的對象。

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

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

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

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

相關文章

  • 詳解IntelliJ IDEA多窗口項目管理技巧

    詳解IntelliJ IDEA多窗口項目管理技巧

    IntelliJ IDEA默認每次打開項目都會新建窗口,可通過設置強制單窗口多項目切換或默認多開項目,下面就來介紹一下IntelliJ IDEA多窗口項目管理技巧,感興趣的可以了解一下
    2025-09-09
  • 帶你重新認識Java動態(tài)代理

    帶你重新認識Java動態(tài)代理

    這篇文章主要為大家介紹了Java的動態(tài)代理,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • Java BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類用法示例

    Java BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類用法示例

    這篇文章主要介紹了Java BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類用法,結合實例形式詳細分析了Java使用BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類進行數(shù)值運算與日期運算相關操作技巧,需要的朋友可以參考下
    2019-03-03
  • Java實現(xiàn)雪花算法的原理

    Java實現(xiàn)雪花算法的原理

    這篇文章主要介紹了Java實現(xiàn)雪花算法的原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • SpringCloud微服務應用config配置中心詳解

    SpringCloud微服務應用config配置中心詳解

    這篇文章主要介紹了SpringCloud微服務應用-config配置中心,包括相關知識介紹、搭建、動態(tài)刷新、測試,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • Java中Cglib代理類重寫邏輯詳解

    Java中Cglib代理類重寫邏輯詳解

    這篇文章主要介紹了Java中Cglib代理類重寫邏輯詳解,代理類中只會維護NoOp這個回調(diào)屬性,并不會生成目標類MyService中的noOp所對應的方法,需要的朋友可以參考下
    2023-11-11
  • Java中使用json與前臺Ajax數(shù)據(jù)交互的方法

    Java中使用json與前臺Ajax數(shù)據(jù)交互的方法

    這篇文章主要為大家詳細介紹了Java中使用json與前臺Ajax數(shù)據(jù)交互的方法,分享Ajax獲取顯示Json數(shù)據(jù)的一種方法,感興趣的小伙伴們可以參考一下
    2016-06-06
  • SpringBoot項目實用功能之實現(xiàn)自定義參數(shù)解析器

    SpringBoot項目實用功能之實現(xiàn)自定義參數(shù)解析器

    這篇文章主要介紹了SpringBoot項目實用功能之實現(xiàn)自定義參數(shù)解析器,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SWT(JFace)體驗之List演示匯總

    SWT(JFace)體驗之List演示匯總

    SWT(JFace)體驗之List演示代碼匯總
    2009-06-06
  • SpringBoot部署xxl-job方法詳細講解

    SpringBoot部署xxl-job方法詳細講解

    XXL-JOB是一個分布式任務調(diào)度平臺,其核心設計目標是開發(fā)迅速、學習簡單、輕量級、易擴展,這篇文章主要介紹了springboot整合xxl-job流程,需要的朋友可以參考下
    2023-01-01

最新評論

黔西| 霍州市| 临沧市| 定日县| 友谊县| 建阳市| 蓬莱市| 个旧市| 肥西县| 岑巩县| 新郑市| 仁寿县| 新郑市| 井研县| 河曲县| 东兰县| 德令哈市| 荔浦县| 遂川县| 永春县| 开平市| 都江堰市| 桐柏县| 黔西县| 新密市| 通州区| 循化| 凌海市| 平潭县| 夏津县| 承德县| 普安县| 龙井市| 章丘市| 曲水县| 重庆市| 赣州市| 紫阳县| 莱阳市| 鹤峰县| 库伦旗|