пружина - инжекция конструктора и переопределяющий родительское определение вложенного боба

Я считал ссылку Spring 3 на наследовавшихся бобовых определениях, но я смущен тем, что возможно и не возможно.

Например, боб, который берет боб сотрудника, настроенный со значением 12


    



     
    

Я затем хотел бы смочь создать подобные бобы с немного отличающимися настроенными сотрудниками. Я могу сделать что-то как

   
       
          
             
          
       
   

Я не уверен, что это возможно и, если это было, это чувствует себя немного неуклюжим. Существует ли более хороший способ переопределить мелкие детали большого вложенного бобового определения? Кажется, что дочерний боб должен знать довольно много о родителе, например, индексе конструктора.

Это - игрушечный пример - на практике, сервис является большим бобовым определением, полагающимся на многие другие бобы сотрудника, которые имеют также другие бобовые зависимости. Например, цепочка обработчиков были созданы с каждым бобом, ссылающимся на следующее в цепочке, которая ссылается на следующее. Я хочу создать почти идентичную цепочку с некоторыми небольшими изменениями в обработчиках в середине, как делают меня это?

Я предпочел бы не изменять структуру - сервисные бобы используют сотрудников для выполнения их функции, но я могу добавить свойства и использовать инжекцию свойства, если это помогает.

Это - повторный шаблон, был бы, создавая пользовательскую справку схемы?

Спасибо за любой совет!

Править: Кусок моего вопроса, если у меня есть действительно большое бобовое определение с комплексом hiearchy создаваемых бобов (боб, имеющий properites, которые являются бобом и т.д.), и я хочу создать боб, который является почти тем же с несколькими изменениями, как я делаю это? Упомяните, должно ли Ваше решение использовать properites, или если инжекция конструктора может использоваться.

Вложенный по сравнению с бобами верхнего уровня не проблема (на самом деле, я думаю, что все бобы являются верхним уровнем на практике.)

EDIT2: Спасибо за Ваши ответы до сих пор. FactoryBean мог бы быть ответом, так как это уменьшит сложность пружинного контекста и позволит мне указывать просто различия как параметры к фабрике. Но, продвижение блока контекста назад в код не чувствует себя хорошо. Я услышал, той пружиной может использоваться со сценариями, например, отличный - который обеспечивает альтернативу? Фабрика могла быть создана в отличном?

9
задан mdma 20 May 2010 в 23:32
поделиться

4 ответа

Я не совсем уверен, чего вы пытаетесь достичь. Я не думаю, что вы можете добиться именно того, чего хотите, без создания собственной настраиваемой схемы (что нетривиально для вложенных структур), но следующий пример, вероятно, довольно близок без этого.

Сначала определите абстрактный 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>

Поскольку все Honda Civics имеют один и тот же двигатель (в моем мире, где я ничего не знаю об автомобилях), я даю ему вложенный компонент двигателя по умолчанию. К сожалению, компонент не может ссылаться на абстрактный компонент, поэтому механизм по умолчанию не может быть абстрактным. Я определил конкретный 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>

Теперь я могу определить свой конкретный автомобиль, взяв все значения по умолчанию, ссылаясь на bean-компонент, в котором они определены через parent :

<bean id="myCar" parent="defaultCar"/>

У моей жены есть машина, такая же, как у меня, за исключением другой модели (опять же, я ничего не знаю о машинах - давайте предположим, что двигатели такие же, хотя в реальной жизни они, вероятно, не такие). Вместо переопределения кучи компонентов / свойств я просто снова расширяю определение автомобиля по умолчанию, но переопределяю одно из его свойств:

<bean id="myWifesCar" parent="defaultCar">
    <property name="model" value="Odyssey"/>
</bean>

У моей сестры такая же машина, как у моей жены (правда), но она другого цвета.Я могу расширить конкретный компонент и переопределить одно или несколько его свойств:

<bean id="mySistersCar" parent="myWifesCar">
    <property name="color" value="Silver"/>
</bean>

Если мне нравятся гоночные минивэны, я мог бы подумать о том, чтобы приобрести один с более мощным двигателем. Здесь я расширяю bean-компонент минивэна, заменяя его двигатель по умолчанию новым двигателем. Этот новый механизм расширяет механизм по умолчанию, переопределяя несколько свойств:

<bean id="supedUpMiniVan" parent="myWifesCar">
    <property name="engine">
        <bean parent="defaultEngine">
            <property name="volume" value="600"/>
            <property name="weight" value="750"/>
        </bean>
    </property>
</bean>

Вы также можете сделать это более кратко, используя вложенные свойства :

<bean id="supedUpMiniVan" parent="myWifesCar">
    <property name="engine.volume" value="600"/>
    <property name="engine.weight" value="750"/>
</bean>

Это будет использовать "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>

Я думаю, что этот пример дает основную идею. Если ваша структура данных сложна, вы можете определить несколько абстрактных bean-компонентов или создать несколько разных абстрактных иерархий, особенно если ваша иерархия bean-компонентов глубже двух bean-компонентов.

Дополнительное примечание: в моем примере используются свойства, которые, как мне кажется, гораздо проще понять как в Spring xml, так и в Java-коде. Однако точно такая же техника работает для конструкторов, фабричных методов и т. Д.

12
ответ дан 4 December 2019 в 11:04
поделиться

Ваш пример не будет работать так, как указано, потому что определение вложенного компонента не имеет указанного класса или родительского . Вам нужно будет добавить дополнительную информацию, например:

<bean name="beanService13" parent="beanService12">
   <constructor-arg index="0">
      <bean parent="beanBaseNested">
         <constructor-arg index="0" value="13"/>
      </bean>
   </constructor>

Хотя я не уверен, допустимо ли ссылаться на вложенные bean-компоненты по такому имени.

К определениям вложенных компонентов следует относиться с осторожностью; они могут быстро стать нечитаемыми. Вместо этого рассмотрите возможность определения внутренних bean-компонентов как bean-компонентов верхнего уровня, что упростит чтение определений внешних bean-компонентов.

Что касается дочерних bean-компонентов, которым необходимо знать индекс конструктора родительского bean-компонента, это более основная проблема с внедрением конструктора Java, поскольку аргументы конструктора Java не могут упоминаться по имени, только по индексу. Внедрение сеттера почти всегда более читабельно за счет потери окончательности внедрения конструктора.

Пользовательская схема - это всегда вариант, как вы упомянули, хотя ее довольно сложно настроить. Если вы обнаружите, что часто используете этот шаблон, возможно, оно того стоит.

6
ответ дан 4 December 2019 в 11:04
поделиться

Думали ли вы об использовании вместо фабрики?

Вы можете сконфигурировать bean-компоненты так, чтобы они имели фабрику, и вы могли бы закодировать различные параметры при создании фабрики ...

1
ответ дан 4 December 2019 в 11:04
поделиться

Чтобы расширить фабричный паттерн от Патрика: вы можете использовать прототип bean-компонента для получения предварительно подключенных зависимостей:

<bean id="protoBean" scope="prototype">
 <property name="dependency1" ref="some bean" />
 <property name="dependency2" ref="some other bean" />
 ...
</bean>

Теперь это работает лучше всего, если вы используете внедрение установщика (а не аргументы конструктора), я не уверен вы даже можете сделать это, если вам потребуются аргументы конструктора.

public class PrototypeConsumingBean implements ApplicationContextAware {

 public void dynmicallyCreateService(String serviceParam) {
   // creates a new instance because scope="prototype"
   MyService newServiceInstance = (MyService)springContext.getBean("protoBean");
   newServiceInstance.setParam(serviceParam);
   newServiceInstance.mySetup();
   myServices.add(newServiceInstance);
 }

 public void setApplicationContext(ApplicationContext ctx) {
  m_springContext = ctx;
 }
}
0
ответ дан 4 December 2019 в 11:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: