15

I am having some trouble getting some Spring configuration to be applied in the desired order with Spring Boot in a multi-module Maven project.

I have modules A and B that are written by me and a dependency on a third party module that I have no control over in module C (dependencies are as follows: A depends on C, B depends on A)

In module A I have a class annotated with @Configuration and also @AutoConfigureBefore(ClassFromModuleD.class). In module B I have another class annotated with @Configuration and also @AutoConfigureBefore(ClassFromModuleA.class)

I was hoping that this would result in the bean definitions in my module B being configured first, followed by beans in my module A configuration class then finally the ones in C.

I also tried adding a META-INF/spring.factories file to both module A and B which declares the single configuration file present in its own module. E.g. for module A

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.exmaple.moduleAConfiguration

and in module B:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.exmaple.moduleBConfiguration

I am not seeing the desired order of configuration, in fact, it seems to be the exact opposite to what I want. I have used logging statements and a debugger to step through and it seems the config from Module C is applied first, followed by A then finally B.

Could anyone point out what I may have missed or if there is another way to do this? thanks very much in advance.

David
  • 7,652
  • 21
  • 60
  • 98
  • Can you show your main configuration class? What do you mean by "configured" (how do you know that one thing comes before another at euntime)? – Dave Syer Dec 27 '14 at 15:25
  • The main configuration class looks like this: `@EnableReactor @SpringBootApplication public class SpringConfiguration { }` I believe that the order isn't what I desire because I've put breakpoints in the various bean definition methods and they aren't being hit in the order that I hoped for. The trouble is, a bean in module C tries to lookup a bean in the context which isn't there yet because it is configured by modules A and B which haven't been autoconfigured yet... If I step through the code runs for module C and then some time later the beans get configured (too late)! – David Dec 27 '14 at 15:33
  • 1
    The `AutoconfigureBefore/After` annotations only apply to the order the classes are imported into the bean factory. They don't say anything about the order that beans are created so your break points are not really helping to understand the problem. If a bean cannot be created there must be an error and a stack trace, so maybe it would help to post those? – Dave Syer Dec 27 '14 at 15:38
  • Why is the bean in module C "looking up" a bean in the context (I assume this means calling `getBean`) instead of letting the container auto-wire said bean. The latter would also ensure that the required bean would be created before the bean in module C. – hzpz Jul 29 '15 at 18:23
  • You said "@AutoConfigureBefore(ClassFromModuleD.class)" But nowhere else in your post do you mention anything about a Module D. Is this a typo? Did you mean to say "@AutoConfigureBefore(ClassFromModuleC.class)"? – axiopisty Dec 11 '22 at 07:59

1 Answers1

9

Spring AutoConfiguration is used to provide a basic configuration if certain classes are in the classpath or not.

This is used e.g. to provide a basic Jpa configuration if Hibernate is on the classpath.

If you want to configure the order in which beans are instantiated by spring you can use

@DependsOn("A") 
public class B{
...    
}

This would create bean "A", than "B".

However, the order you desire may not be possible. You wrote :

A depends on C, B depends on A

If 'depends on' means : A needs C to be instantiated, the beans must be created in the following order :

  1. C - because C depends on nothing
  2. A - because A depends on C, which is already created.
  3. B - because B depends on A, which is already created.

Spring automatically detects the dependencies by analyzing the bean classes.

If A has an autowired property or a constructor argument of type C, spring 'knows' that it must instantiate C before A.

In most cases this works quite well.

In some cases spring cannot 'guess' the dependencies and creates beans in an unwanted order. Than you can 'inform' spring through the @DependsOn annotation about the dependency. Spring will try to change the order accordingly.

In your case, if the dependencies you described are not visible for spring, and the dependencies are not needed to create the beans, you can try to change the order with @DependsOn :

A depends on C, B depends on A

Could be achieved with

@DependsOn("C") 
public class A{
   ...    
}

@DependsOn("A") 
public class B{
   ...    
}

// C comes from another module
// and no need to annotate