第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Spring 中的作用域代理是什么?

Spring 中的作用域代理是什么?

呼啦一陣風(fēng) 2023-09-13 16:45:05
正如我們所知,Spring 使用代理來添加功能(@Transactional例如@Scheduled)。有兩種選擇 - 使用 JDK 動態(tài)代理(該類必須實現(xiàn)非空接口),或使用 CGLIB 代碼生成器生成子類。我一直認(rèn)為 proxyMode 允許我在 JDK 動態(tài)代理和 CGLIB 之間進(jìn)行選擇。但我能夠創(chuàng)建一個例子來表明我的假設(shè)是錯誤的:情況1:單例:@Servicepublic class MyBeanA {    @Autowired    private MyBeanB myBeanB;    public void foo() {        System.out.println(myBeanB.getCounter());    }    public MyBeanB getMyBeanB() {        return myBeanB;    }}原型:@Service@Scope(value = "prototype")public class MyBeanB {    private static final AtomicLong COUNTER = new AtomicLong(0);    private Long index;    public MyBeanB() {        index = COUNTER.getAndIncrement();        System.out.println("constructor invocation:" + index);    }    @Transactional // just to force Spring to create a proxy    public long getCounter() {        return index;    }}主要的:MyBeanA beanA = context.getBean(MyBeanA.class);beanA.foo();beanA.foo();MyBeanB myBeanB = beanA.getMyBeanB();System.out.println("counter: " + myBeanB.getCounter() + ", class=" + myBeanB.getClass());輸出:constructor invocation:000counter: 0, class=class test.pack.MyBeanB$$EnhancerBySpringCGLIB$$2f3d648e在這里我們可以看到兩件事:MyBeanB僅被實例化一次。為了添加 的@Transactional功能MyBeanB,Spring 使用了 CGLIB。案例2:讓我糾正一下MyBeanB定義:@Service@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)public class MyBeanB {在這種情況下,輸出是:constructor invocation:00constructor invocation:11constructor invocation:2counter: 2, class=class test.pack.MyBeanB$$EnhancerBySpringCGLIB$$b06d71f2在這里我們可以看到兩件事:MyBeanB被實例化3次。為了添加 的@Transactional功能MyBeanB,Spring 使用了 CGLIB。你能解釋一下發(fā)生了什么事嗎?代理模式到底如何工作?
查看完整描述

1 回答

?
蕪湖不蕪

TA貢獻(xiàn)1796條經(jīng)驗 獲得超7個贊

為行為生成的代理@Transactional與作用域代理具有不同的用途。

代理@Transactional是一種包裝特定 bean 以添加會話管理行為的代理。所有方法調(diào)用都將在委托給實際 bean 之前和之后執(zhí)行事務(wù)管理。

如果你舉例說明的話,它看起來像

main?->?getCounter?->?(cglib-proxy?->?MyBeanB)

出于我們的目的,您基本上可以忽略它的行為(刪除@Transactional后您應(yīng)該看到相同的行為,除非您沒有 cglib 代理)。

代理@Scope的行為有所不同。文檔指出:

[...]您需要注入一個代理對象,該對象公開與作用域?qū)ο笙嗤墓步涌冢?strong>但也可以從相關(guān)作用域(例如 HTTP 請求)檢索真實目標(biāo)對象,并將方法調(diào)用委托給真實對象。

Spring 真正做的是為代表代理的工廠類型創(chuàng)建一個單例 bean 定義。然而,相應(yīng)的代理對象會在每次調(diào)用時查詢上下文以獲取實際的 bean。

如果你舉例說明的話,它看起來像

main?->?getCounter?->?(cglib-scoped-proxy?->?context/bean-factory?->?new?MyBeanB)

由于MyBeanB是原型 bean,上下文將始終返回一個新實例。

出于本答案的目的,假設(shè)您MyBeanB直接使用

MyBeanB?beanB?=?context.getBean(MyBeanB.class);

這本質(zhì)上就是 Spring 為滿足@Autowired注入目標(biāo)所做的事情。


在你的第一個例子中,

@Service

@Scope(value = "prototype")

public class MyBeanB {?

您聲明原型 bean定義(通過注釋)。@Scope有一個proxyMode元素

指定組件是否應(yīng)配置為作用域代理,如果是,則代理是否應(yīng)基于接口或基于子類。

默認(rèn)為ScopedProxyMode.DEFAULT,這通常表示不應(yīng)創(chuàng)建作用域代理,除非在組件掃描指令級別配置了不同的默認(rèn)值。

因此 Spring 不會為生成的 bean 創(chuàng)建作用域代理。您可以使用以下命令檢索該 bean

MyBeanB?beanB?=?context.getBean(MyBeanB.class);

您現(xiàn)在擁有對 Spring 創(chuàng)建的新對象的引用MyBeanB。這與任何其他 Java 對象一樣,方法調(diào)用將直接轉(zhuǎn)到引用的實例。

如果再次使用getBean(MyBeanB.class),Spring 將返回一個新實例,因為 bean 定義是針對原型 bean的。您沒有這樣做,因此所有方法調(diào)用都會轉(zhuǎn)到同一個對象。


在你的第二個例子中,

@Service

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)

public class MyBeanB {

您聲明一個通過 cglib 實現(xiàn)的作用域代理。當(dāng)從 Spring 請求這種類型的 bean 時

MyBeanB?beanB?=?context.getBean(MyBeanB.class);

Spring知道這MyBeanB是一個作用域代理,因此返回一個滿足API的代理對象MyBeanB(即實現(xiàn)其所有公共方法),該對象內(nèi)部知道如何MyBeanB為每個方法調(diào)用檢索實際的bean類型。

嘗試跑步

System.out.println("singleton?:?"?+?(context.getBean(MyBeanB.class)?==?context.getBean(MyBeanB.class)));

這將返回true暗示 Spring 返回一個單例代理對象(而不是原型 bean)的事實。

在代理實現(xiàn)內(nèi)部的方法調(diào)用上,Spring 將使用一個特殊getBean版本,該版本知道如何區(qū)分代理定義和實際MyBeanBbean 定義。這將返回一個新MyBeanB實例(因為它是原型),Spring 將通過反射將方法調(diào)用委托給它(經(jīng)典Method.invoke)。


您的第三個示例與第二個示例基本相同。


查看完整回答
反對 回復(fù) 2023-09-13
  • 1 回答
  • 0 關(guān)注
  • 147 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號