In Spring you can have ApplicationContexts form a hierarchy, one contexts is said to be the parent of another one. There isn't much documentation about what this means in practice. Basically it means "if you ask the child context for a bean and it doesn't have a definition for it, it will consult its parent context". But how does this extend to abstract beans or dependencies?

What I want to achieve is that I define a concrete implementation of a bean in the parent context and allow the child context to override some of its settings. My preference would be an option where the child context cannot change the class backing the bean and where I can restrict the properties the child context is allowed to override to a certain set, this is what I tried:

  <beans ...>
    <!-- parent -->
    <bean id="abstractHello" abstract="true">
      <property name="message" value="inside parent context"/>
    </bean>

    <bean id="concreteHello" parent="abstractHello"
          class="springtests.Hello" scope="prototype"/>
  </beans>

  <beans ...>
    <!-- child -->
    <bean id="abstractHello" abstract="true">
      <property name="message" value="inside child context"/>
    </bean>
  </beans>

with a simple bean that has a setter for a String "message" property. Unfortunately this doesn't work as I hoped, "concreteHello" retrieved from the child context has a message of "inside parent context".

So what about dependencies instead of inheritance? I introduce a simple "holder" object and inject it into my bean:

  <beans ...>
    <!-- parent -->
    <bean id="holder" class="springtests.MessageHolder">
      <property name="message" value="inside parent context"/>
    </bean>

    <bean id="helloFromHolder" class="springtests.Hello" scope="prototype">
      <property name="messageHolder" ref="holder"/>
    </bean>
  </beans>

  <beans ...>
    <!-- child -->
    <bean id="holder" class="springtests.MessageHolder">
      <property name="message" value="inside child context"/>
    </bean>
  </beans>

Which leads to the same result. When "helloFromHolder" gets configured, it won't see the "holder" reference of the child context.

To be honest, the behavior I've seen is what I had expected, but I thought I could try anyway.

I settled with allowing the child context to completely override the parent bean. But I wrote my own NamespaceHandler code (and bumped into a bunch of gotchas for another post) which prevents setting of properties that shouldn't be overridden and doesn't allow setting the class. Something like

  <beans ...>
    <!-- parent -->
    <bean id="abstractHello" class="springtests.Hello" abstract="true">
      <property name="message" value="inside parent context"/>
    </bean>

    <bean id="hello" parent="abstractHello"/>
  </beans>

  <beans ...>
    <!-- child -->
    <override:hello>
      <override:message>inside child context</override:message>
    </override:hello>
  </beans>

Here the "abstractHello" bean provides the class and default parameters and the NamespaceHandler doesn't allow setting id (it will always be "hello"), parent (always abstractHello), class or any of the other attributes that might be available. Unfortunately I can't prevent the child context from using "plain" Spring bean definitions to completely override "hello".

path: /en/Java/Spring | #