2014-09-30 34 views
1

我正在使用一些現有的代碼,它正在做我以前沒見過的事情。我已經使用方法注入將原型bean自動裝入單例,或者使用getBean()從上下文獲取bean。我在這段代碼中看到的是一個bean,它是一個原型並使用getBean()進行檢索,並且它具有自動裝配的依賴關係。其中大部分是單身豆,這是有道理的。但是有另一個原型bean的自動裝載,從我看來,它看起來好像正在獲得一個新的bean。我的問題是,當你將原型自動裝入原型時,是否會給你一個新的實例?由於autowire請求不是在啓動時創建的,而是在創建這個bean的時候,它是否會創建一個新的實例?這違背了我對autowire和prototype beans的看法,我想聽到外面的答案。感謝您的任何見解。我試圖儘量減少對代碼的重構,因爲它有點意大利麪條。將原型bean的Autowire插入原型bean中?

例如:

@Scope("prototype") 
public class MyPrototypeClass { 

    @Autowired 
    private ReallyGoodSingletonService svc; 

    @Autowired 
    private APrototypeBean bean; 

    public void doSomething() { 
     bean.doAThing(); 
    } 
} 

@Scope("prototype) 
public class APrototypeBean { 
    private int stuffgoeshere; 

    public void doAThing() { 
    } 
} 

所以當DoSomething的()在MyPrototypeClass叫,是「豆」一個單身或MyPrototypeClass的每個實例一個新的?

回答

10

在你的例子中,APrototypeBean bean將被設置爲一個全新的bean,它將一直存在,直到你創建的MyPrototypeClass的實例被銷燬。

如果您創建MyPrototypeClass的第二個實例,那麼第二個實例將收到它自己的APrototypeBean。使用您當前的配置,每當您撥打doSomething()時,該方法將在APrototypeBean的實例上調用,該實例對該MyPrototypeClass對象是唯一的。

+0

好的解釋@馬克拉倫 – 2016-06-30 15:05:22

1

您對@Autowired或自動裝配的瞭解通常是有缺陷的。自動裝配在創建bean的實例時發生,而不是在啓動時發生。

如果您將有一個懶惰的單例bean,並且沒有直接使用bean,只要您在應用程序上下文中使用例如getBean來檢索bean,就會創建一個實例,依賴關係會得到連接,BeanPostProcessors得到應用等。

這是每一個類型的豆,它將被處理,只要它不是在此之前創建它是相同的。

現在要回答你的問題,一個原型bean是一個原型bean,所以是的,你會收到新的實例,每次調用getBean

+0

謝謝 - 所以我明白,使用getBean檢索bean會爲您提供一個新實例。這就是原型的定義。但是在這個bean的內部,如果有一個原型範圍bean的自動裝載,那麼它是否也創建了該bean的新實例?這是我以前從未見過的。 – titania424 2014-10-01 14:55:45

+0

爲什麼不應該。正如我在創建bean時所說明的那樣,它注入了它的依賴關係,這些依賴關係也是使用'getBean'檢索的,所以同樣適用。我想我的答案已經很清楚了。創建時刻也是注入,代理創建等時刻,應用程序上下文不關心的範圍。 – 2014-10-01 17:32:53

0

向@Mark Laren的答案添加更多解釋。

Spring 4.1.6 docs

說明在大多數應用場景,最豆在容器是 單身。當一個單例bean需要與另一個單例bean協作時,或者一個非單例bean需要與另一個非單例bean協作時,通常需要將依賴關係定義爲 ,將一個bean定義爲另一個bean的屬性。當豆類生命週期不同時,會出現問題 。假設單例bean A需要 使用非單例(原型)bean B,也許在每個方法 上調用A.容器只創建一個單例bean A, ,因此只有一次機會來設置屬性。 容器無法向bean A提供一個新的bean B實例,每 需要一次。

下方接近將解決這個問題,但這不是理想因爲Spring框架和違反 IOC模式的代碼夫婦的業務代碼。以下是這種方法的一個例子:

// a class that uses a stateful Command-style class to perform some processing 
package fiona.apple; 

// Spring-API imports 
import org.springframework.beans.BeansException; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 

public class CommandManager implements ApplicationContextAware { 

    private ApplicationContext applicationContext; 

    public Object process(Map commandState) { 
     // grab a new instance of the appropriate Command 
     Command command = createCommand(); 
     // set the state on the (hopefully brand new) Command instance 
     command.setState(commandState); 
     return command.execute(); 
    } 

    protected Command createCommand() { 
     // notice the Spring API dependency! 
     return this.applicationContext.getBean("command", Command.class); 
    } 

    public void setApplicationContext(
      ApplicationContext applicationContext) throws BeansException { 
     this.applicationContext = applicationContext; 
    } 
} 

所以,有2個理想的方法來解決這個問題。

1.使用Spring的方法注入

  • 正如名字所暗示的,Spring將實施&如果您使用XML版本使用@Lookup註釋從春4或標記注入我們的抽象方法。請參閱this DZone article

通過使用@Lookup。

從Java文檔...

的註釋,表示「查找」的方法,由 容器覆蓋,以他們重定向回Bean工廠的電話的getBean。 這實質上是XML lookup-method屬性的基於註釋的版本,從而產生相同的運行時間排列。

時間: 4.1

@Component 
public class MyClass1 { 
    doSomething() { 
    myClass2(); 
    } 

    //I want this method to return MyClass2 prototype 
    @Lookup 
    public MyClass2 myClass2(){ 
    return null; // No need to declare this method as "abstract" method as 
       //we were doing with earlier versions of Spring & <lookup-method> xml version. 
       //Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically. 
    } 
} 

上面的例子將創建新myClass2實例中的每個時間。

2.使用Java EE提供程序(依賴注入Java(JSR 330))。

@Scope(BeanDefinition.SCOPE_PROTOTYPE) 
    @Component 
    public static class SomeRequest {} 

    @Service 
    public static class SomeService { 

     @Autowired 
     javax.inject.Provider<SomeRequest> someRequestProvider; 

     SomeRequest doSomething() { 
      return someRequestProvider.get(); 
     } 
    } 

上面的例子將每次創建新的SomeRequest實例。

相關問題