spring - 构造函数注入和覆盖嵌套bean的父定义

mdm*_*dma 9 java spring

我已经阅读了关于继承bean定义的Spring 3参考,但我对可能和不可能的内容感到困惑.

例如,一个带有协作者bean的bean,配置值为12

<bean name="beanService12" class="SomeSevice">
    <constructor-arg index="0" ref="serviceCollaborator1"/>
</bean>

<bean name="serviceCollaborator1" class="SomeCollaborator">
    <constructor-arg index="0" value="12"/> 
    <!-- more cargs, more beans, more flavor -->
</bean>
Run Code Online (Sandbox Code Playgroud)

然后,我希望能够创建类似的bean,配置略有不同的协作者.我能做点什么吗

   <bean name="beanService13" parent="beanService12">
       <constructor-arg index="0">
          <bean>
             <constructor-arg index="0" value="13"/>
          </bean>
       </constructor>
   </bean>
Run Code Online (Sandbox Code Playgroud)

我不确定这是否可能,如果是的话,感觉有点笨拙.是否有更好的方法来覆盖大型嵌套bean定义的小部分?似乎子bean必须非常了解父类,例如构造函数索引.

这是一个玩具示例 - 实际上,服务是依赖于许多其他协作者bean的大型bean定义,这些bean还具有其他bean依赖性.例如,创建了一系列处理程序,每个bean引用链中的下一个,引用下一个.我想创建一个几乎完全相同的链,中间的处理程序有一些小的变化,我该怎么做?

我不想改变结构 - 服务bean使用协作者来执行他们的功能,但我可以添加属性并使用属性注入,如果这有帮助的话.

这是一个重复的模式,会创建自定义架构帮助吗?

谢谢你的建议!

编辑:我的问题的核心是,如果我有一个非常大的bean定义,创建一个复杂的bean的bean(bean有正确的bean等),我想创建一个几乎相同的bean一些变化,我该怎么做?如果您的解决方案必须使用适当的,或者可以使用构造函数注入,请提及.

嵌套与顶级bean不是问题(事实上,我认为所有bean都是实践中的顶级bean.)

EDIT2:到目前为止,感谢您的回答.FactoryBean可能就是答案,因为这会降低spring上下文的复杂性,并允许我仅将差异指定为工厂的参数.但是,将一大块上下文推回到代码中并不合适.我听说spring可以和脚本一起使用,比如groovy - 那提供了另一种选择吗?工厂可以在groovy中创建吗?

Sin*_*hot 12

我不完全确定你想要实现的目标.我不认为你可以在不创建自己的自定义模式的情况下实现你想要的东西(这对于嵌套结构来说是非常重要的),但下面的例子可能非常接近而不这样做.

首先,定义一个抽象bean作为外部bean的模板(我的例子使用Car作为外部bean,Engine作为内部bean),给出所有其他bean可以继承的默认值:

<bean id="defaultCar" class="Car" abstract="true">
    <property name="make" value="Honda"/>
    <property name="model" value="Civic"/>
    <property name="color" value="Green"/>
    <property name="numberOfWheels" value="4"/>
    <property name="engine" ref="defaultEngine"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

由于所有Honda Civics都有相同的引擎(在我的世界里,我对汽车一无所知),我给它一个默认的嵌套引擎bean.不幸的是,bean无法引用抽象bean,因此默认引擎不能是抽象的.我为引擎定义了一个具体的bean,但是将它标记为lazy-init不会实际实例化,除非另一个bean使用它:

<bean id="defaultEngine" class="Engine" lazy-init="true">
    <property name="numberOfCylinders" value="4"/>
    <property name="volume" value="400"/>
    <property name="weight" value="475"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

现在我可以定义我的特定汽车,通过引用定义它们的bean来获取所有默认值parent:

<bean id="myCar" parent="defaultCar"/>
Run Code Online (Sandbox Code Playgroud)

我的妻子就像我的车一样,除了它的车型不同(再一次,我对汽车一无所知 - 让我们假设发动机是相同的,即使在现实生活中他们可能不是).我没有重新定义一堆bean /属性,而是再次扩展默认汽车定义,但覆盖其中一个属性:

<bean id="myWifesCar" parent="defaultCar">
    <property name="model" value="Odyssey"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

我的姐姐和我的妻子(真的)有同样的车,但它有不同的颜色.我可以扩展一个具体的bean并覆盖它上面的一个或多个属性:

<bean id="mySistersCar" parent="myWifesCar">
    <property name="color" value="Silver"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

如果我喜欢赛车迷你车,我可能会考虑让一辆更大的发动机.在这里,我扩展了一个小型货车豆,用新引擎覆盖它的默认引擎.这个新引擎扩展了默认引擎,覆盖了一些属性:

<bean id="supedUpMiniVan" parent="myWifesCar">
    <property name="engine">
        <bean parent="defaultEngine">
            <property name="volume" value="600"/>
            <property name="weight" value="750"/>
        </bean>
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

您还可以使用嵌套属性更简洁地执行此操作:

<bean id="supedUpMiniVan" parent="myWifesCar">
    <property name="engine.volume" value="600"/>
    <property name="engine.weight" value="750"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

这将使用"defaultEngine".但是,如果您以这种方式创建两辆汽车,每辆汽车具有不同的属性值,则行为将不正确.这是因为两辆车将共享相同的引擎实例,第二辆车将覆盖第一辆车上设置的属性设置.这可以通过将defaultEngine标记为"原型"来解决,每次引用它时都会实例化一个新原型:

<bean id="defaultEngine" class="Engine" scope="prototype">
    <property name="numberOfCylinders" value="4"/>
    <property name="volume" value="400"/>
    <property name="weight" value="475"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

我认为这个例子给出了基本的想法.如果您的数据结构很复杂,您可以定义多个抽象bean,或者创建几个不同的抽象层次结构 - 特别是如果您的bean层次结构比两个bean更深.

旁注:我的示例使用属性,我相信在Spring xml和Java代码中都可以更清楚地理解这些属性.但是,完全相同的技术适用于构造函数,工厂方法等.


ska*_*man 6

您的示例将无法按指定的方式工作,因为嵌套的bean定义没有class或未parent指定.您需要添加更多信息,例如:

<bean name="beanService13" parent="beanService12">
   <constructor-arg index="0">
      <bean parent="beanBaseNested">
         <constructor-arg index="0" value="13"/>
      </bean>
   </constructor>
Run Code Online (Sandbox Code Playgroud)

虽然我不确定这样的名称引用嵌套bean是否有效.

应谨慎对待嵌套bean定义; 它们很快就会升级为不可读性.考虑将内部bean定义为顶级bean,这将使外部bean定义更容易阅读.

至于需要知道父bean的构造函数索引的子bean,这是Java构造函数注入的一个更基本的问题,因为Java构造函数参数不能通过名称引用,只能引用索引.Setter注入几乎总是更具可读性,代价是失去了构造函数注入的最终结果.

正如您所提到的,自定义模式始终是一个选项,尽管设置起来有点痛苦.如果您发现自己经常使用这种模式,那么可能值得付出努力.