2016-09-27 61 views
0

我想在使用Bean的@Bean類型定義時使用Spring的bean繼承。具體來說,讓如何使用@Bean註釋配置子Bean

public class Serwis { 
    Integer a; 
    Integer b; 
    Map<Integer, Integer> m = new HashMap<>(); 
} 

,並假設基於XML的配置看起來像:

<bean id="absSerwis" class="service.Serwis" 
     p:a="11"> 
    <property name="m"> 
     <map> 
      <entry key="111" value="111"></entry> 
     </map> 
    </property> 
</bean> 

<bean id="defSerwis" parent="absSerwis" 
     p:b="12" 
    /> 

這確實創建一個包含豆absSerwis的深層副本豆defSerwis;特別是m的內容被複制。現在,我想定義豆類喜歡用@Bean註解defSerwis,像

@Autowired 
@Qualifier("absSerwis") 
private Serwis absSerwis; 

@Bean 
public Serwis cccSerwis() { 
    Serwis s = new Serwis(); 
    BeanUtils.copyProperties(absSerwis, s); //wrong; does shallow copy 
    return s; 
} 

是什麼做的正確方法?

+1

你對家長的理解是有點偏離。它所做的只是將兩個bean定義合併在一起,然後構建事物。它沒有形成一個深刻的/新鮮的副本,沒有這樣的事情。只要創建一個方法來創建你的'absSerwis'(注意不用'@ Bean'註釋它!)。然後創建2個'@ Bean'方法,1顯示原始信號'absSerwis',另一個添加一些屬性。 –

+0

@ M.Deinum「一點點」:這可能是這種情況:)。你能否指出一個能夠詳細闡述xml的父類如何工作的地方。 –

+0

查看我的回答(以及鏈接,參考Spring參考指南)。 –

回答

1

對於你形容也不爲實際發生的事情首發。沒有深層複製或其他任何東西。讓我們先調查一下Spring在使用parent bean時會做些什麼。 (另請注意,它是關於bean定義繼承不是類繼承!);

鑑於您的配置

<bean id="absSerwis" class="service.Serwis" 
     p:a="11"> 
    <property name="m"> 
     <map> 
      <entry key="111" value="111"></entry> 
     </map> 
    </property> 
</bean> 

<bean id="defSerwis" parent="absSerwis" 
     p:b="12" 
    /> 

會發生什麼情況是,對於defSerwis定義它需要父absSerwis的配置和本身併合併成一個完整的bean定義這一點。因此沒有深層副本或豆類副本。

什麼春天終於看到

<bean id="absSerwis" class="service.Serwis" 
     p:a="11"> 
    <property name="m"> 
     <map> 
      <entry key="111" value="111"></entry> 
     </map> 
    </property> 
</bean> 

<bean id="defSerwis" class="service.Serwis" 
     p:a="11" p:b="12" 
     <property name="m"> 
     <map> 
      <entry key="111" value="111"></entry> 
     </map> 
    </property> 
    /> 

也看到了參考指南this section

最簡單的方法是創建一個構建父項的方法,並從那裏添加。此方法必須而不是註明@Bean

@Configuration 
public class MyConfiguration { 

    private Serwis baseSerwis() { 
     Serwis base = new Serwis(); 
     base.setA(11); 
     Map map = new HashMap(); 
     map.put(111, 111); 
     base.setM(map); 
     return base; 
    } 

    @Bean 
    public Serwis absSerwis() { 
     return baseSerwis(); 
    } 

    @Bean 
    public Serwis defSerwis() { 
     Serwis defSerwis = baseSerwis(); 
     defSerwis.setB(12); 
     return defSerwis; 
    } 
} 

這或多或少相當於xml部分。

+0

酷;感謝您的精心製作! –

0

如果你想使對象的深層副本,那麼你可以:

1)程序它自己這樣做。 2)使用java序列化(序列化和反序列化可以創建深層副本),但是這需要數據結構中的所有對象都實現可序列化的接口。還有其他自由可以用於這個(例如xStream)。 3)默認情況下,Spring只創建一個特定bean(又名Singleton)的實例,你可以用@Prototype來註釋它,讓Spring知道你想在每次需要它的時候獲得一個新對象。

0

通過使用生成器+複製方法

public class Serwis { 
    Integer a; 
    Integer b; 
    Map<Integer, Integer> m = new HashMap<>(); 

    private Serwis(Builder builder) { 
     a = builder.a; 
     b = builder.b; 
     m = builder.m; 
    } 

    public static Builder builder() { 
     return new Builder(); 
    } 

    public Builder copy(Serwis copy) { 
     return builder() 
      .a(a) 
      .b(b) 
      .m(m); 
    } 

    public static final class Builder { 
     private Integer a; 
     private Integer b; 
     private Map<Integer, Integer> m = new HashMap<>(); 

     private Builder() { 
     } 

     public Builder a(Integer val) { 
      a = val; 
      return this; 
     } 

     public Builder b(Integer val) { 
      b = val; 
      return this; 
     } 

     public Builder m(Map<Integer, Integer> val) { 
      m.putAll(val); 
      return this; 
     } 

     public Serwis build() { 
      return new Serwis(this); 
     } 
    } 
} 

而且配置類是這樣的:

@Autowired 
@Qualifier("absSerwis") 
private Serwis absSerwis; 

@Bean 
public Serwis cccSerwis() { 
    return absSerwis.copy().build(); 
} 
+0

請注意,我正在使用這個數以百計的豆,並且我正在考慮轉換到@Bean,因爲它有很多優點。不用編寫自定義的構建器/深層拷貝,我可以簡單地使用基於xml的配置,這是自動的,我們有比如''。 –

相關問題