AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

Spring AOP 中被代理的對象一定是單例嗎?

來源: 責編: 時間:2023-10-10 18:32:50 538觀看
導讀今天我們來思考這樣一個問題:在 Spring AOP 中,被代理的對象是單例的嗎?當我們每次獲取到代理對象的時候,都會重新獲取一個新的被代理對象嗎?還是被代理的對象始終是同一個?為什么要思考這個問題,因為在松哥接下來要講的 @Sc

今天我們來思考這樣一個問題:在 Spring AOP 中,被代理的對象是單例的嗎?當我們每次獲取到代理對象的時候,都會重新獲取一個新的被代理對象嗎?還是被代理的對象始終是同一個?FRa28資訊網——每日最新資訊28at.com

為什么要思考這個問題,因為在松哥接下來要講的 @Scope 注解高級用法中涉及到這個知識點。FRa28資訊網——每日最新資訊28at.com

1. 問題呈現

假設我有如下一個計算器接口:FRa28資訊網——每日最新資訊28at.com

public interface ICalculator {    void add(int a, int b);    int minus(int a, int b);}

然后給這個接口提供一個實現類:FRa28資訊網——每日最新資訊28at.com

public class CalculatorImpl implements ICalculator {    @Override    public void add(int a, int b) {        System.out.println(a + "+" + b + "=" + (a + b));    }    @Override    public int minus(int a, int b) {        return a - b;    }}

現在假設我要生成一個代理對象,利用編程式的方式,代碼如下:FRa28資訊網——每日最新資訊28at.com

ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(new CalculatorImpl());proxyFactory.addInterface(ICalculator.class);proxyFactory.addAdvice(new MethodInterceptor() {    @Override    public Object invoke(MethodInvocation invocation) throws Throwable {        Method method = invocation.getMethod();        String name = method.getName();        System.out.println(name+" 方法開始執行了。。。");        Object proceed = invocation.proceed();        System.out.println(name+" 方法執行結束了。。。");        return proceed;    }});ICalculator calculator = (ICalculator) proxyFactory.getProxy();calculator.add(3, 4);

這里幾個方法應該都好理解:FRa28資訊網——每日最新資訊28at.com

  1. setTarget 方法是設置真正的被代理對象。這個在我們之前的 @Lazy 注解為啥就能破解死循環?一文中大家已經接觸過了。
  2. addInterface,基于 JDK 的動態代理是需要有接口的,這個方法就是設置代理對象的接口。
  3. addAdvice 方法就是添加增強/通知。
  4. 最后通過 getProxy 方法獲取到一個代理對象然后去執行。

最終打印結果如下:FRa28資訊網——每日最新資訊28at.com

圖片圖片FRa28資訊網——每日最新資訊28at.com

這是一個簡單的 AOP 案例。FRa28資訊網——每日最新資訊28at.com

現在我們的問題在于 setTarget 方法上。FRa28資訊網——每日最新資訊28at.com

我們點進來到 setTarget 方法上看一下這個方法做了什么:FRa28資訊網——每日最新資訊28at.com

public void setTarget(Object target) { setTargetSource(new SingletonTargetSource(target));}

小伙伴們看到,setTarget 方法內部調用了 setTargetSource 方法,這個方法設置了一個 SingletonTargetSource 來作為 targetSource,從名字上就能看出來,這個 SingletonTargetSource 是一個單例的 targetSource。FRa28資訊網——每日最新資訊28at.com

因此,對于上面的代碼,我們可以推斷,多個不同的代理對象中持有的相同的被代理對象,例如下面這段代碼:FRa28資訊網——每日最新資訊28at.com

ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(new CalculatorImpl());proxyFactory.addInterface(ICalculator.class);proxyFactory.addAdvice(new MethodInterceptor() {    @Override    public Object invoke(MethodInvocation invocation) throws Throwable {        Method method = invocation.getMethod();        String name = method.getName();        System.out.println(name+" 方法開始執行了。。。");        Object proceed = invocation.proceed();        System.out.println(name+" 方法執行結束了。。。");        return proceed;    }});ICalculator calculator = (ICalculator) proxyFactory.getProxy();ICalculator calculator2 = (ICalculator) proxyFactory.getProxy();calculator2.add(2, 3);

我們分別獲取了 calculator 和 calculator2 兩個代理對象,但是實際上,這兩個代理對象中持有的是同一個被代理對象,如下圖:FRa28資訊網——每日最新資訊28at.com

圖片圖片FRa28資訊網——每日最新資訊28at.com

從這張圖可以看出,代理對象不是同一個,但是被代理對象其實是同一個。FRa28資訊網——每日最新資訊28at.com

2. TargetSource

在 Spring AOP 中,否則處理代理對象的接口是 TargetSource,TargetSource 有諸多實現類,不同實現類具備不同的能力:FRa28資訊網——每日最新資訊28at.com

圖片圖片FRa28資訊網——每日最新資訊28at.com

很多實現類單純從名字上就能看出來其特點了。FRa28資訊網——每日最新資訊28at.com

我們先來看下 TargetSource 接口:FRa28資訊網——每日最新資訊28at.com

public interface TargetSource extends TargetClassAware { @Override @Nullable Class<?> getTargetClass(); boolean isStatic(); @Nullable Object getTarget() throws Exception; void releaseTarget(Object target) throws Exception;}

這個接口一共是四個方法:FRa28資訊網——每日最新資訊28at.com

  1. getTargetClass:這個是返回被代理對象的類型。
  2. isStatic:這個方法判斷被代理對象是否是不變的,也可以理解為返回被代理對象是否是單例的,不過這個方法并不控制單例的實現,這個方法存在意義在于,如果該方法返回 true,表示被代理的對象是單例的,那么將來就不用調用 releaseTarget 方法去釋放對象,反之,如果這個方法返回 false,表示被代理的對象不是單例的,那么就需要在使用完被代理的對象之后,調用 releaseTarget 方法將之釋放掉。
  3. getTarget:這個方法就是返回被代理對象。
  4. releaseTarget:釋放被代理的對象。

TargetSource 的實現類比較多,我們來看幾個典型的實現類。FRa28資訊網——每日最新資訊28at.com

2.1 SingletonTargetSource

先來看這個類的定義:FRa28資訊網——每日最新資訊28at.com

public class SingletonTargetSource implements TargetSource, Serializable {    @SuppressWarnings("serial") private final Object target; public SingletonTargetSource(Object target) {  Assert.notNull(target, "Target object must not be null");  this.target = target; } @Override public Class<?> getTargetClass() {  return this.target.getClass(); } @Override public Object getTarget() {  return this.target; } @Override public void releaseTarget(Object target) {  // nothing to do } @Override public boolean isStatic() {  return true; }}

如果被代理的對象是單例的,那么我們就會選擇使用 SingletonTargetSource,被代理的對象總是在 getTarget 方法中被調用,然而這個方法返回的總是同一個對象,所以最終被代理的對象就是單例的。FRa28資訊網——每日最新資訊28at.com

同時,由于被代理對象是單例的,因此 isStatic 方法返回 true,releaseTarget 中不需要額外操作。FRa28資訊網——每日最新資訊28at.com

2.2 SimpleBeanTargetSource

SimpleBeanTargetSource 比較典型,這個是每當需要的時候,就去 Spring 容器中查找相應的被代理的 Bean,至于這個被代理的 Bean 是否為單例,就由 Spring 容器來控制了:FRa28資訊網——每日最新資訊28at.com

public class SimpleBeanTargetSource extends AbstractBeanFactoryBasedTargetSource { @Override public Object getTarget() throws Exception {  return getBeanFactory().getBean(getTargetBeanName()); }}public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSource, BeanFactoryAware, Serializable { @Nullable private String targetBeanName; @Nullable private volatile Class<?> targetClass; @Nullable private BeanFactory beanFactory; public void setTargetBeanName(String targetBeanName) {  this.targetBeanName = targetBeanName; } public String getTargetBeanName() {  Assert.state(this.targetBeanName != null, "Target bean name not set");  return this.targetBeanName; } public void setTargetClass(Class<?> targetClass) {  this.targetClass = targetClass; } @Override public void setBeanFactory(BeanFactory beanFactory) {  this.beanFactory = beanFactory; } public BeanFactory getBeanFactory() {  Assert.state(this.beanFactory != null, "BeanFactory not set");  return this.beanFactory; } @Override @Nullable public Class<?> getTargetClass() {  Class<?> targetClass = this.targetClass;  if (targetClass != null) {   return targetClass;  }  synchronized (this) {   targetClass = this.targetClass;   if (targetClass == null && this.beanFactory != null && this.targetBeanName != null) {    targetClass = this.beanFactory.getType(this.targetBeanName);    if (targetClass == null) {     Object beanInstance = this.beanFactory.getBean(this.targetBeanName);     targetClass = beanInstance.getClass();    }    this.targetClass = targetClass;   }   return targetClass;  } } @Override public boolean isStatic() {  return false; } @Override public void releaseTarget(Object target) throws Exception {  // Nothing to do here. }}

從上面這段源碼中大家可以看到,SimpleBeanTargetSource 在使用的時候,需要傳入 targetBeanName,也就是被代理的 bean 名稱,還需要傳入 Spring 容器 BeanFactory,這樣,在每次需要被代理對象的時候去調用 getTarget 方法的時候,就直接從容器中查詢出來目標 Bean。因此,被代理的對象到底是不是單例,就要看 Spring 容器返回的對象到底是不是單例!FRa28資訊網——每日最新資訊28at.com

小伙伴們要記著 SimpleBeanTargetSource 的特點,因為在下一篇文章中,松哥要和大家聊的 @Scope 注解的高級用法,就涉及到這一點了。FRa28資訊網——每日最新資訊28at.com

2.3 LazyInitTargetSource

LazyInitTargetSource 有點類似于 SimpleBeanTargetSource,也是從 Spring 容器中查找被代理的 Bean,不同的是,LazyInitTargetSource 具備延遲初始化的能力,也就是在第一次進行調用的時候才會去獲取被代理對象:FRa28資訊網——每日最新資訊28at.com

public class LazyInitTargetSource extends AbstractBeanFactoryBasedTargetSource { @Nullable private Object target; @Override public synchronized Object getTarget() throws BeansException {  if (this.target == null) {   this.target = getBeanFactory().getBean(getTargetBeanName());   postProcessTargetObject(this.target);  }  return this.target; } protected void postProcessTargetObject(Object targetObject) { }}

好啦,其他的類我就不挨個說了,感興趣的小伙伴可以自行查看,這一塊的源碼還是比較好理解的~FRa28資訊網——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-12767-0.htmlSpring AOP 中被代理的對象一定是單例嗎?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Promise 和 Async/Await的區別

下一篇: 亞馬遜計劃向韓國云計算基礎設施再投資58.5億美元

標簽:
  • 熱門焦點
  • 5月iOS設備好評榜:iPhone 14僅排第43?

    來到新的一月,安兔兔的各個榜單又重新匯總了數據,像安卓陣營的榜單都有著比較大的變動,不過iOS由于設備的更新換代并沒有那么快,所以相對來說變化并不大,特別是iOS好評榜,老款設
  • Raft算法:保障分布式系統共識的穩健之道

    1. 什么是Raft算法?Raft 是英文”Reliable、Replicated、Redundant、And Fault-Tolerant”(“可靠、可復制、可冗余、可容錯”)的首字母縮寫。Raft算法是一種用于在分布式系統
  • 線程通訊的三種方法!通俗易懂

    線程通信是指多個線程之間通過某種機制進行協調和交互,例如,線程等待和通知機制就是線程通訊的主要手段之一。 在 Java 中,線程等待和通知的實現手段有以下幾種方式:Object 類下
  • 十個簡單但很有用的Python裝飾器

    裝飾器(Decorators)是Python中一種強大而靈活的功能,用于修改或增強函數或類的行為。裝飾器本質上是一個函數,它接受另一個函數或類作為參數,并返回一個新的函數或類。它們通常用
  • 如何使用JavaScript創建一只圖像放大鏡?

    譯者 | 布加迪審校 | 重樓如果您曾經瀏覽過購物網站,可能遇到過圖像放大功能。它可以讓您放大圖像的特定區域,以便瀏覽。結合這個小小的重要功能可以大大改善您網站的用戶體驗
  • 零售大模型“干中學”,攀爬數字化珠峰

    文/侯煜編輯/cc來源/華爾街科技眼對于絕大多數登山愛好者而言,攀爬珠穆朗瑪峰可謂終極目標。攀登珠峰的商業路線有兩條,一是尼泊爾境內的南坡路線,一是中國境內的北坡路線。相
  • 東方甄選單飛:有些鳥注定是關不住的

    文/彭寬鴻編輯/羅卿東方甄選創始人俞敏洪帶隊的&ldquo;7天甘肅行&rdquo;直播活動已在近日順利收官。成立后一年多時間里,東方甄選要脫離抖音自立門戶的傳聞不絕于耳,&ldquo;7
  • 三星電子Q2營收60萬億韓元 存儲業務營收同比仍下滑超過50%

    7月27日消息,據外媒報道,從三星電子所發布的財報來看,他們主要利潤來源的存儲芯片業務在今年二季度仍不樂觀,營收同比仍在大幅下滑,所在的設備解決方案
  • 支持aptX Lossless無損傳輸 iQOO TWS 1賽道版發布限時優惠價369元

    2023年7月4日,“無損音質,聲動人心”iQOO TWS 1正式發布,支持aptX Lossless無損傳輸,限時優惠價369元。iQOO TWS 1耳機率先支持端到端aptX Lossless無
Top