Использовать абстрактный компонент Spring в качестве аргумента-конструктора

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

public abstract class AbstractHandler {
  public AbstractHandler(final AbstractHandler next, final PropertyName propertyName) {
    this.next = next;
    this.propertyName = propertyName;
  }
  ...  

public class OneConcreteChildHandler extends AbstractHandler {
  public OneConcreteChildHandler(final AbstractHandler next) {
    super(next, PropertyName.OneConcreteChild);
  }
  ...

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

<bean id="abstractHandler" abstract="true" class="...AbstractHandler" />

<bean id="oneConcreteChildHandler" class="...OneConcreteChildHandler" parent="abstractHandler">
    <constructor-arg ref="abstractHandler"/> //"abstract bean can not be used here"
</bean>

<bean id="someService" class="...SomeService">
    <constructor-arg ref="oneConcreteChildHandler"/>
    ...

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


person hammerfest    schedule 02.05.2017    source источник


Ответы (2)


Основная проблема здесь в том, что вы пытаетесь внедрить абстрактный компонент. Вы не должны этого делать. Этот abstractHandler следует использовать только для сопоставления parent в дочернем компоненте. Несмотря на это, это не похоже на то, что вы хотите/нужно. Вы бы не передавали абстрактный объект в этот конструктор, а объект другого дочернего класса. Ваша цепочка должна иметь конечную точку, где аргумент конструктора next будет нулевым, например:

<bean id="abstractHandler" abstract="true" class="...AbstractHandler" />

<bean id="oneConcreteChildHandler" class="...OneConcreteChildHandler" parent="abstractHandler">
        <constructor-arg ref="twoConcreteChildHandler"/>
    </bean>

<bean id="twoConcreteChildHandler" class=".." parent="abstractHandler">
    <constructor-arg name="next">
        <null />
    </constructor-arg>
</bean>

<bean id="someService" class="...SomeService">
    <constructor-arg ref="oneConcreteChildHandler"/>
    ...
person Bruno    schedule 02.05.2017
comment
Спасибо. Мы только что заметили, что среди конкретных дочерних классов на самом деле существует класс TailChildHandler для замыкания цепочки CoR (его конструктор содержит super(null,null)) и мы можем использовать его в конфиге так же, как twoConcreteChildHandler в вашем пример. Это решает проблему. - person hammerfest; 02.05.2017

Концепция абстрактного компонента Spring НЕ совпадает с концепцией абстрактного класса Java.

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

Вместо этого я бы рекомендовал вам посмотреть, как работают фильтры сервлетов (через FilterChain) или шаблон Spring HandlerInterceptor.

person nicholas.hauschild    schedule 02.05.2017