Announcement Announcement Module
No announcement yet.
Unexpected behaviour with multiple config files Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unexpected behaviour with multiple config files

    Hi all,

    I've found some odd behaviour when using multiple config files for my Spring context, and I'd like to know if it's a bug... or just working as designed. :wink:

    Here's a reduced example using Spring 1.1.3. First, a trivial interface and two trivial implementations:

    public interface I {}
    public class A implements I {}
    public class B implements I {}

    Now, two very simple Spring config files that let me create an A or a B:

    <beans><bean id="Bean" class="A"/></beans>
    <beans><bean id="Bean" class="B"/></beans>

    Now, some code to create the context, get an instance of I, and print out which implementation class was instantiated:

    context = new ClassPathXmlApplicationContext&#40; new String&#91;&#93;&#123; "a.xml", "b.xml" &#125; &#41; ;
    System.out.println&#40; context.getBean&#40; "Bean", I.class &#41;.getClass&#40;&#41;.getName&#40;&#41; &#41; ;

    When I run that code as is, "B" is printed out, meaning the second config file overrode the first one. Of course, if I reverse the order of the two config files, then "A" is printed out. If I use only one of the files, then "A" or "B" is printed out, as appropriate.


    Now, if I go with the original code, using "a.xml" followed by "b.xml", and if I remove, then I of course get an error that Spring couldn't create "Bean" since class B is missing:

    org.springframework.beans.factory.BeanDefinitionStoreException&#58; Error registering bean with name 'Bean' defined in class path resource &#91;b.xml&#93;&#58; Bean class &#91;B&#93; not found; nested exception is java.lang.ClassNotFoundException&#58; B
    That makes sense.

    What does NOT make sense is what happens when I put back and remove I get an exception that class A is missing, even though it would never be instantiated! :shock:

    org.springframework.beans.factory.BeanDefinitionStoreException&#58; Error registering bean with name 'Bean' defined in class path resource &#91;a.xml&#93;&#58; Bean class &#91;A&#93; not found; nested exception is java.lang.ClassNotFoundException&#58; A

    My assumption was that any bean definition that is over-ridden in a later file would be ignored (of course it would still need to parse properly).

    In my particular situation, I had a production config file which instantiated an MQ Series queue connection. Rather than modify that file, I tried to override the MQSeries definition by creating a second file defining something that would work in my environment, but Spring didn't like it. Spring expected me to have all the MQ libraries in my dev environment, even though I was not going to use them.

    (I got around it by pulling out the MQ definition, and now we have *two* files in production, one big one with common stuff, followed by a smaller file with bits specific to the environment. But this may not always be an option.)

    Is this the "correct" behaviour?



  • #2
    It depends on your lazy-init settings. If the beans are not lazy initializated then Spring will search for the class definition right after parsing. For your case I would suggest to mark the approapriate beans to be lazy so only the latest definition (after parsing all the files) is used.


    • #3
      I was using lazy-init, actually, and it didn't seem to help.

      Changing my example, above, like this (changing both files):

      <beans default-lazy-init="true">
          <bean id="Bean" class="A"/>
      still gives the same behaviour.


      • #4
        Have you tried placing A as lazy and B as non lazy? Anyways I think you need a different approach to solve this problem - some sort of strategy. You can either supply just one file and you have to manually take care of packaging or do a switch case in your code - based on the environment you know which file to load...but I guess you thought of this anyway


        • #5
          Hmmmm, if I have to handle it through code, then I'm guessing it's a bug? :wink:

          Like I said, I found a way around it by abstracting out any beans that might be 'unavailable' in a given environment.

          I just wondered if this was the desired behaviour, before I go and enter a bug report.




          • #6
            I think it's the desired behaviour., however I haven't written the code so I don't know if the authors had this behavior clearly in mind .
            The documentation states that abstract beans are not instantiated (but their definition can be reused), while concrete beans are instantiated - I didn't find anything about overridding though.
            One thing you could try is aggregate the defintions in one file. Instead of giving the files as different arguments (a.xml, b.xml) try to include them in only one file using <import> :


            • #7
              This behaviour is completely normal. Any singleton bean is by default going to be pre-instantiated by the container, whether or not it's referred to by another bean.

              If this is not desireable, you have two options. If the bean does need to be created at some point, you need to mark it as lazy-init. Alternately, if the bean is simply an abstract parent definition for another bean (and referred to via the 'parent' attribute, then you should set the 'abstract' attribute to true.


              • #8
                Hmm, scratch my last reply, I see that you were using lazy. However, Spring does need the class to be available when reading bean definitions. The class gets stored with the bean definition.

                You might try filing a Jira enhancement request to defer the class loading until later. However, this would have the effect of letting you know of errors in your ocntext definitions much later (potentially), so I don't know if it's a desireable change.