1. 程式人生 > >轉--解決Spring中singleton的Bean依賴於prototype的Bean的問題

轉--解決Spring中singleton的Bean依賴於prototype的Bean的問題

原文連結:https://my.oschina.net/itblog/blog/205860

scope="prototype"沒寫的問題,專案中對一個表的增刪該操作是用一個action,這個actionadd,update,delete,save這些方法, 新增和修改是共用一個頁面,當頁面得到id時代表進行的修改操作,反之是新增操作。因為在配置spring的bean是忘了寫scope="prototype" 所以每次新增時都顯示最後一次訪問過的記錄,scope="prototype" 會在該型別的物件被請求 時建立一個新的action物件。如果沒有配置scope=prototype則新增的時候不會新建一個action,他任然會保留上次訪問的過記錄的資訊 webwork的Action不是執行緒安全的,要求在多執行緒環境下必須是一個執行緒對應一個獨立的例項,不能使用singleton。所以,我們在Spring配置Webwork Action Bean時,需要加上屬性scope=”prototype”或singleton=”false”。 
singleton模式指的是對某個物件的完全共享,包括程式碼空間和資料空間,說白了,如果一個類是singleton的,假如這個類有成員變數,那麼這個成員變數的值是各個執行緒共享的(有點類似於static的樣子了),當執行緒A往給變數賦了一個值以後,執行緒B就能讀出這個值。因此,對於前臺Action,肯定不能使用singleton的模式,必須是一個執行緒請求對應一個獨立的例項。推而廣之,只要是帶資料成員變數的類,為了防止多個執行緒混用資料,就不能使用singleton。對於我們用到的Service、Dao,之所以用了singleton,就是因為他們沒有用到資料成員變數,如果誰的Service需要資料成員變數,請設定singleton=false。 有狀態的bean都使用Prototype作用域,而對無狀態的bean則應該使用singleton作用域。

另外,當Spring容器中作用域不同的Bean相互依賴時,可能出現一些問題,例如:一個作用域為Singleton的Bean(設為A)依賴於一個作用域為prototype的Bean(設為B)。由於A是單例的,只有一次初始化的機會,它的依賴關係也只在初始化階段被設定,但它所依賴的B每次都會建立一個全新的例項,這將使A中的B不能及時得到更新。這樣將導致如果客戶端多次請求A,並呼叫A中B的某個方法(或獲取A中B的某個屬性),服務端總是返回同一個B,但客戶端直接請求B卻能獲得最新的物件,這就產生了物件不同步的情況。這樣就違背了B初衷:本來希望B具有prototype的行為,但是卻表現出singleton的行為了。那麼,問題如何解決呢?

    辦法有二:

  • 部分放棄依賴注入:當A每次需要B時,主動向容器請求新的Bean例項,即可保證每次注入的B都是最新的例項。

  • 利用方法注入。

    第一種方式顯然不是一個好的做法,程式碼主動請求Bean例項,必然導致程式碼與SpringAPI耦合在一起,造成嚴重的程式碼汙染。通常情況下,我們會採用第二種做法。使用方法注入。

    方法注入通常使用lookup方法注入,利用lookup方法注入可以讓Spring容器重寫容器中Bean的抽象或具體方法,返回查詢容器中其他Bean的結果,被查詢的Bean通常是一個non-singleton的Bean(儘管也可以是一個singleton的Bean)。Spring通過使用CGLIB庫修改客戶端的二進位制碼,從而實現上述要求。看下面的例子:

public abstract class Developer implements Person {
    public Developer() {
        System.out.println("Spring例項化主調的Bean...Developer例項");
    }
    //定義一個抽象方法,該方法將由Spring實現
    public abstract Phone getPhone();
    @Override
    public void call() {
        System.out.println("正在使用 " + getPhone() + " 打電話");
        System.out.println(getPhone().call());
    }
}

    上面的CellPhone將被部署成prototype的Bean,並被一個singleton的Bean所依賴。如果讓Spring容器直接將prototype的Bean注入到singleton中,就會出現上面的問題。為了解決這個問題,我們在singleton的Bean裡增加一個抽象方法,該方法的返回型別是一個被依賴的Bean——注意這個方法是一個抽象方法,因為程式中沒有為該方法提供實現,這個實現過程由Spring完成。下面是該singleton作用域的Bean的程式碼:

public abstract class Developer implements Person {
    public Developer() {
        System.out.println("Spring例項化主調的Bean...Developer例項");
    }
    //定義一個抽象方法,該方法將由Spring實現
    public abstract Phone getPhone();
    @Override
    public void call() {
        System.out.println("正在使用 " + getPhone() + " 打電話");
        System.out.println(getPhone().call());
    }
}


    上面的程式碼定義了一個抽象的getPhone方法,通常情況下,程式不能呼叫這個方法,但Spring框架將會負責為該方法提供是先提,這樣這個方法就會變成具體方法了,程式也就可以呼叫該方法了。為了讓Spring知道如何實現該方法,我們需要在配置檔案中使用<lookup-method>標籤,這個標籤需要指定如下兩個屬性:

  • name:指定需要讓Spring實現的方法

  • bean:指定Spring實現該方法後返回的值

    下面是配置片段:

<!-- 將CellPhone部署成prototype的範圍 -->
<bean id="cellPhone" class="com.abc.CellPhone" scope="prototype" />
<bean id="developer" class="com.abc.Developer">
    <!-- getPhone方法返回CellPhone,每次呼叫將獲取新的CellPhone -->
    <lookup-method name="getPhone" bean="cellPhone" />
</bean>

    上面配置的<lookup-method>指定Spring將負責實現getPhone方法,該方法將返回容器中的prototype型別的cellPhone例項。下面是測試類:

public class Test {
    public static void main(String args[]) {
        ApplicationContext context = 
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Developer d = context.getBean("developer", Developer.class);
        d.call();
        d.call();
    }
}

    執行結果如下:

Spring例項化主調的Bean...Developer例項
Spring例項化依賴的Bean...CellPhone例項
正在使用 [email protected] 打電話
Spring例項化依賴的Bean...CellPhone例項
正在打電話...
Spring例項化依賴的Bean...CellPhone例項
正在使用 [email protected] 打電話
Spring例項化依賴的Bean...CellPhone例項
正在打電話...

    結果表明:當lookup方法注入後,系統每次呼叫getPhone都會返回最新的CellPhone例項而非最早的CellPhone例項。

    注意:要保證lookup方法注入每次產生的Bean例項,必須將目標Bean(本例為cellPhone)佈署成prototype作用域。否則,如果容器中只有一個目標Bean例項,即使採用lookup方法注入,每次依然返回同一個Bean例項。另外,lookup方法注入不僅能用於設值注入,還能用於構造注入。

相關推薦

--解決Springsingleton的Bean依賴prototype的Bean的問題

原文連結:https://my.oschina.net/itblog/blog/205860 scope="prototype"沒寫的問題,專案中對一個表的增刪該操作是用一個action,這個actionadd,update,delete,save這些方法, 新增和修改是共

spring對控制反轉和依賴注入的理解

由於最近沒有太多時間,不能深入的瞭解控制反轉和依賴注入,只好把別人的理解轉載過來,非常痛恨市面上各種教程對所謂的術語張口就來,等自己有了時間一定要寫出新手都能看懂的教程。     首先想說說IoC(Inversion of Control,控制反轉)。這是spring的核心,貫穿始終。所謂IoC

spring依賴檢查

ram 5.x 集合類型 name style 基本類 all cep 檢查 4個依賴檢查支持的模式: none – 沒有依賴檢查,這是默認的模式。 simple – 如果基本類型(int, long,double…)和集合類型(map, list..)的任何屬性都沒有設

解決Spring使用context:component-scan命名空間配置錯誤

num lex odi exceptio type oca ted pac instance ** nested exception is org.xml.sax.SAXParseException; lineNumber: 16; columnNumber: 74; cv

Spring @Autowired標籤與 @Resource標籤 的區別

Spring不但支援自己定義的@Autowired註解,還支援由JSR-250規範定義的幾個註解,如:@Resource、 @PostConstruct及@PreDestroy。 1. @Autowired    @Autowired是Spring 提供的,需匯入  

深入理解Spring核心技術---Spring依賴注入

         在前面的幾篇部落格中給大家介紹了Spring中的IOC容器,現在大家應該都知道IOC容器的概念和實現的原理了吧,IOC容器是Spring的核心,他的功能就是幫助開發者去儲存物件以及管理物件之間的關係。不用讓開發者自己去管理物件之間的關係,使開發者只需要專注於

如何解決spring同一個類裡面方法之間呼叫的時候註解失效的問題

參考部落格:https://blog.csdn.net/z55887/article/details/81073450 @RestController public class Test { @Autowired ApplicationContext context;

Spring迴圈依賴的正確性與Bean注入的順序關係

一、前言 最近在做專案時候遇到一個奇葩問題,就是bean依賴注入的正確性與bean直接注入的順序有關係,但是正常情況下明明是和順序沒關係的啊,究竟啥情況那,不急,讓我一一道來。 二、普通Bean迴圈依賴-與注入順序無關 2.1 迴圈依賴例子與原理 public class BeanA {

解決SpringQuart無法自動注入Bean問題

        因專案需求,之前專案中已經有定時器的例子了,但是需求那邊過來的需求之前用的定時器並不能滿足,之前的定時器是用spring裡面的@Scheduled(cron = "0 0 0 * * ? ")這種方式,這是一種死的定時器,需求要的是動態定時器,使用者新增一個

解決spring不同配置檔案存在name或者id相同的bean可能引起的問題

spring對同一配置檔案中相同id或者name的兩個或以上的bean時,做直接拋異常的處理,而對不同配置檔案中相同id或者名稱的bean,只會在列印日誌級別為info的資訊,資訊內容大概為"Overriding bean definition for bean xxx :

Java日誌框架——JCL(Log4J,Java Logging API)SLF4J過程重複依賴衝突問題

如文章《Java日誌框架——JCL(Log4J,Java Logging API)轉SLF4J》所述,在完成”JCL(Log4J,Java Logging API)轉SLF4J“的過程中,要注意重複依賴衝突問題。 比如一個專案原本使用JCL日誌框架(可以是具有對"commo

Spring各種依賴注入的程式碼實現

DI:Spring稱之為依賴注入,就是維護物件和物件之間的關係 通俗的講,就是 給類的成員賦值。 1、屬性賦值: class A{ String str = “Hello Word !” } 注入: <bean id="A" class="類A

Spring 配置sessionFactory及用法(JAVA後端)

編輯 刪除 Spring 中配置sessionFactory及用法 方法一: 1、在Spring的applicationContext.xml中配置bean  <!-- 啟用註解注入  -->       <context:annota

Spring依賴查詢和依賴注入

作者:[Grey](https://www.cnblogs.com/greyzeng/) 原文地址: [語雀](https://www.yuque.com/greyzeng/mnc4mc/oshvxb) [部落格園](https://www.cnblogs.com/greyzeng/p/14459565

[]使用@Test 也可以從spring容器獲取依賴註入

oca fig article ring1 detail ice 如果 text resource 轉自:http://blog.csdn.net/u010987379/article/details/52091790 @RunWith(SpringJUnit4Cla

Spring Bean迴圈依賴解決方案

在迴圈依賴是指在A中引用B,B中引用C,而C中引用A,容器建立物件時會出現死迴圈。相關解決方案如下: 1 選擇其一使其延遲載入,然後從上下文中獲取AService型別的bean即可。 現有AService 和BService,都在對方bean中注入,導致初始化時迴圈初始報錯,解決方案就是

Spring-IOC-Bean的初始化-循環依賴解決

creation reference single 填充 hash 可能 target get 完美 前言 在實際工作中,經常由於設計不佳或者各種因素,導致類之間相互依賴。這些類可能單獨使用時不會出問題,但是在使用Spring進行管理的時候可能就會拋出BeanCurren

Spring的IOC(控制反轉)與DI(依賴注入)理解由淺入深-適用小白

IOC(Inversion of Control )與 DI(Dependency injection)是sping的主要思想,不是技術! IOC控制反轉:一般我們在一個類中呼叫其它的類(非靜態類),需要新建一個該類的例項或者從其他途徑獲取該類的例項,然後對通過該例項進行操

》mavenimport scope依賴方式解決單繼承問題的理解

在maven多模組專案中,為了保持模組間依賴的統一,常規做法是在parent model中,使用dependencyManagement預定義所有模組需要用到的dependency(依賴) <dependencyManagement>

Spring的迴圈依賴解決詳解

前言         說起Spring中迴圈依賴的解決辦法,相信很多園友們都或多或少的知道一些,但當真的要詳細說明的時候,可能又沒法一下將它講清楚。本文就試著儘自己所能,對此做出一個較詳細的解讀。另,需注意一點,下文中會出現類的例項化跟類的初始化兩個短語,為怕園友迷惑,