Spring Boot - Order of Bean creation - spring

Is there any default bean initialization order implicitly in a Spring Boot application? I came across this question in one of my Spring Boot applications when trying to use #ConditionalOnBean annotation.
At first, I thought that Spring does not guarantee any Bean creation order when it's loading beans in #Configuration class or when it's doing component-scan to auto register #Component/#Service/.. classes.
But later, I noticed that in the Spring documentation, it mentions that,
Auto-configuration classes are guaranteed to load after any user-defined bean definitions have been added.
This somehow makes me confused,
1. What counts user defined bean and what counts auto-configuration classes? Specifically, is there any loading order between #Bean in #Configuration class and #Component/#Service directly on class level.
2. If a bean A needs dependency injection of bean B, will B always be initialized first?
3. If #Import is used for configuration aggregation in a Spring Boot application, will beans defined in the imported configuration class being initialized before component-scanned bean registration.
#Component
public class A {}
#Component
public class B {
#Autowired
private A a;
}
#Configuration
public class externalConfig {
#Bean
public C c() {
return new C();
}
}
#SpringBootApplication
#Import(externalConfig.class)
public class testApplication {
#Bean
public D d() {
return new D();
}
}
When comes to the above code example, my question becomes the following.
1. Without #Import, will C or D always be initialized before A and B?
2. Will B always be initialized before A?
3. With #Import, will C always be initialized first, like even before D?

Not 100% sure, but:
No there is no guarantee.
A will be initialized, then B, cause you're injecting A.
Import is not guaranteeing the order, only if you have some not lazy injections
Check the DependsOn annotation (enter link description here).
I hope it helps you,

Related

when using functional bean registration, is there a way to inform Spring that ClassA is responsible for creating an instance of BeanA?

I've switched a portion of a Spring app to use functional bean registrations. The motivation for the switch is due to requiring multiple instances of some beans under certain conditions. It also turns out to be much more concise (which won't be at all apparent with the simplistic examples below).
The code used to look like this (simple example):
#Configuration
public class ConfigA {
#Bean
public BeanA beanA() {
return new BeanA();
}
}
#Service
public class Service1 {
#Autowired BeanA beanA;
...
}
#Service
public class Service2 {
#Autowired BeanA beanA;
...
}
I've switched the configuration class to look like this:
#Configuration
public class ConfigA implements ApplicationContextInitializer<GenericApplicationContext> {
#Override
public void initialize(GenericApplicationContext context) {
context.registerBean("beanA", BeanA.class, () -> new BeanA());
}
}
The issue I'm now encountering is that Spring is complaining about autowired beans not being found. With the original code, Spring could determine that a BeanA bean was declared via ConfigA and would create that bean before initializing the services.
With the new code, I guess there is no way for Spring to determine where the BeanA bean(s) are being declared, and so it tries to init the services before the BeanA is initialized (which causes the app to not start).
I was hoping that Spring would prioritize #Configuration classes over #Service or #Controller classes, but that doesn't seem to be the case.
I could annotate all the services with #DependsOn("configA"), but there are many services that autowire BeanA (some in other code bases), so the #DependsOn option isn't really realistic.
Question: When using functional bean registration, is there a way to inform Spring that ConfigA is responsible for creating an instance of BeanA?
In order to use the functional style of bean registration and enable autowiring mechanism in other beans you can do the following:
Remove #Configuration annotation from your ConfigA class;
Create directory named META-INF under main/java/resources and create a file named spring.factories under the newly created directory;
Fill the newly created file with the line org.springframework.context.ApplicationContextInitializer=(package-name-to-configA-class).ConfigA
Now Spring should be able to successfully autowire bean named BeanA where requested.

Why #ConditionalOnMissingBean is invoked before the bean it should check?

In my Spring Boot application I want beans to be created only if a module is not enabled.
In CoreConfig I've defined two beans (geocoder and travelDistanceCalculator)
annotated with #ConditionalOnMissingBean referencing the interfaces those beans should initialize.
#Configuration
class CoreConfig {
private val logger = loggerFor<CoreConfig>()
#Bean
#ConditionalOnMissingBean(Geocoder::class)
fun geocoder(): Geocoder {
logger.warn("no Geocoder bean instance has been provided. Instantiating default.")
return object : Geocoder {
override fun getGeocode(address: String) = Coordinates.Unavailable
}
}
#Bean
#ConditionalOnMissingBean(TravelDistanceCalculator::class)
fun travelDistanceCalculator(): TravelDistanceCalculator {
logger.warn("no TravelDistanceCalculator bean instance has been provided. Instantiating default.")
return object : TravelDistanceCalculator {
override fun getTravelDistanceInKm(origin: Coordinates, destination: Coordinates) = Double.NaN
}
}
// other beans definitions...
}
Then GeolocationConfig defines a bean (HereApiClient) implementing both Geocoder and TravelDistanceCalculator interfaces.
#Configuration
#ConditionalOnProperty("app.geolocation.enable")
class GeolocationConfig {
#Bean
fun hereApiClient(
geolocationProperties: GeolocationProperties,
restTemplate: RestTemplate
): HereApiClient =
HereApiClient(restTemplate, geolocationProperties)
}
app.geolocation.enable is defined as true in application.yml.
What happens here is that, on startup, geocoder and travelDistanceCalculator default beans defined in CoreConfig are initialized even if GeolocationConfig is enabled and HereApiClient is initialized shortly after them.
What am I missing here?
ConditionalOnMissingBean is dependent on the order in which #Configuration classes are processed and their beans are defined. In your example, I suspect that CoreConfig is being processed, its conditions evaluated, and its beans defined before your hereApiClient bean has been defined. As a result, when the missing bean conditions are evaluated, there is no matching bean found and the geocoder and travelDistanceCalculator beans are defined.
The javadoc for ConditionalOnMissingBean makes the following recommendation:
The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.
You could follow this recommendation by using #Order on your configuration classes. Alternatively (and preferably, in my opinion) you could make CoreConfig an auto-configuration class by listing it in META-INF/spring.factories under the org.springframework.boot.autoconfigure.EnableAutoConfiguration key and moving it to a package where it will not be picked up by component scanning.
#ConditionalOn(Missing)Bean is intended to be used on auto-configuration classes. see javadoc
If used in common configiruation-classes then the outcome depends on whichever configuration is loaded first. See andy-wilkinson answer
In your case you could easily use the same property (you are already providing) to configure the correct beans.
Use #ConditionalOnProperty(name="app.geolocation.enable") on GeolocationConfig
Use #ConditionalOnProperty(name="app.geolocation.enable",havingValue="false") on/in CoreConfig
EDIT
Use #ConditionalOnProperty(name="app.geolocation.enable",havingValue="false",matchIfMissing = true) if you want the CoreConfig to be used if the property is missing.

Bean overriding in Spring context that uses both annotation and xml config

There is a spring project A which is completely annotation based.
I need to override some beans conditionally in project B which is a legacy application using Spring 4.1.3 and uses xml based config.
There is FooConfig which is configuring beans using #ComponentScan. This config is a third party code for me. i.e I do not have access for this
#ComponentScan(basePackages = {"com.foo.bean"})
#Configuration
public class FooConfig {
}
I have created a BarConfig at my end, which imports this FooConfig and overrides some beans based on a condition. This is achieved using #Conditional
#Configuration
#Import(FooConfig.class)
public class BarConfig {
#Bean(name="helloService")
#Conditional(IsSpanishCondition.class)
public HelloService getHelloService() {
return new HelloService() {
#Override
public String getGreeting(String name) {
return "Hola "+name;
}
};
}
}
And I have included BarConfig in my application-context.xml
<context:annotation-config/>
<bean class="com.foo.config.BarConfig"/>
While this approach works flawlessly in Spring 5.1.2.RELEASE, it does not work in Spring 4.1.3.RELEASE
00:14:20.617 [main] INFO org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader - Skipping bean definition for [BeanMethod:name=getHelloService,declaringClass=com.foo.config.BarConfig]: a definition for bean 'helloService' already exists. This top-level bean definition is considered as an override.
Also, I have observed the same issue in Spring 4 in a completely annotation based context as well. i.e. it is not because of xml and annotation config mix but due to the Spring versions used here
Questions
What changed in Spring 5?
Is there any rule of thumb while working with a Spring application that uses both xml and annotation config especially when it comes to overriding the beans?
Also FTR, these are the solutions that worked
1.Overriding the beans using BeanPostProcessor
2.Using profiles. But this wouldn't work for complicated conditions.
#Profile("ENGLISH")
#Configuration
#Import(FooConfig.class)
public class EnglishConfig {
}
#Profile("SPANISH")
#Configuration
public class SpanishConfig {
#Bean(name="helloService")
public HelloService getHelloService() {
return new HelloService() {
#Override
public String getGreeting(String name) {
return "Hola "+name;
}
};
}
}
The issue here is that you are trying to override a xml bean from a #Configuration class, now I'm not 100% sure, but in spring 4 a xml bean still had precedence in choosing a bean, so the #Configuration beans would not get permission to overwrite the xml bean. Which was resolved in spring 5.
Your approach to use BeanPostProcessor is i guess the only viable solution for this.
I'm thinking maybe you could use a different bean name, implement your own behaviour and use #Qualifier annotation to choose which bean will get selected?

#AutoConfigureAfter not working as desired

I have 3 spring-boot-starter projects
One of the autoconfiguration class has the following code:
#Configuration
#ConditionalOnClass(value = Config.class)
#AutoConfigureAfter(value = {FileGeneratorConfig.class, FileUploaderConfig.class})
public class JobConfig
FileGeneratorConfig and FileUploaderConfig are also autoconfiguration classes.
I was expecting that beans created in FileUploaderConfig will be created first. So test this I had put a break point in the method that creates bean in JobConfig and FileUploaderConfig. But the break point hits JobConfig first which makes me believe that my #AutoConfigureAfter is not working. Is that the right assumption.
Also in FileUploaderConfig i have this:
#Bean
FileUtilContainer fileUtilContainer(FileUtilContainerProperties fileUtilContainerProperties){
return new FileUtilContainer(FileUtil.createDirectory(fileUtilContainerProperties.getArchive()),
FileUtil.createDirectory(fileUtilContainerProperties.getWorking()),
FileUtil.createDirectory(fileUtilContainerProperties.getConfirmation()),
FileUtil.createDirectory(fileUtilContainerProperties.getConfirmationProcessed()),
FileUtil.createDirectory(fileUtilContainerProperties.getError()),
FileUtil.createDirectory(fileUtilContainerProperties.getErrorProcessed()));
}
and FileUtilContainerProperties:
#Component
#ConfigurationProperties(prefix = "batch.letter.directory", ignoreUnknownFields = false)
public class FileUtilContainerProperties
but it is not creating FileUtilContainerProperties bean. Am I missing something here?
AutoConfigureAfter controls the order in which the configuration files are processed and their bean definitions are created. The order in which beans are created from those definitions is a separate concern and depends on, among other things, the dependencies that exist between your beans.

What is the difference between #Configuration and #Component in Spring?

#ComponentScan creates beans using both #Configuration and #Component. Both these annotations work fine when swapped. What is the difference then?
#Configuration Indicates that a class declares one or more #Bean
methods and may be processed by the Spring container to generate bean
definitions and service requests for those beans at runtime
#Component Indicates that an annotated class is a "component". Such
classes are considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.
#Configuration is meta-annotated with #Component, therefore
#Configuration classes are candidates for component scanning
You can see more here:
http://docs.spring.io/spring-framework/docs/4.0.4.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html
A #Configuration is also a #Component, but a #Component cannot act like a #Configuration.
Actually answer is not complete, is it true that:
#Component Indicates that an annotated class is a "component". Such
classes are considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.
But you do can create i.e MyConfiguration.java class then stereotype with #Component and add #Beans declaration to it. In this way it will looks as a configuration, main difference is that when annotated class with #Configuration #Bean annotated methods are proxy using CGLIB which made in code calls after the first one to return bean from context instead of execute method again and create another instance as happens when using #Component with #Bean
There is a very subtle difference between them. Let me provide a very quick outlook to this.
Consider the below scenario:
#Configuration
public class MyConfig {
#Bean
public ServiceA aService(){
return new ServiceA();
}
#Bean
public ServiceB bService(){
return new ServiceB(aService());
}
}
Note that ServiceB bean has a dependecy on ServiceA and this is not autowired. Instead, the way it's written implies that a new instance is created, which is not actually created by Spring. You, the programmer, did it with the new keyword instead.
So, if we do use #Configuration, then it uses CGLIB proxying, and in this situation it creates a singleton bean managed by the Spring context. If you invoke it multiple times, it returns the same bean that was created by Spring - sort of autowiring effect.
Whereas if you use #Component, it won't do this proxying and will simply return a new instance every time the method is invoked, instead of providing the Spring managed instance. (Remember that a Spring bean is something that is managed by the Spring container, and, as a developer, it's your job is to pull them in, e.g. with #Autowired.
The same #Component effect can be achieved with #Configuration(proxyEnabled= false) (This is also referred to as bean light mode processing). So, in light mode, you would end up doing something like this:
#Configuration(proxyEnabled = false) // Lite mode, same effect as #Component
public class MyConfig {
#Bean
public ServiceA aService() {
return new ServiceA();
}
#Autowired
#Bean
public ServiceB bService(ServiceA aServiceBean){
return new ServiceB(aServiceBean);
}
}
Refer here for a more elaborate explanation
Hope that helps! Happy Coding!
#Configuration - It is like beans.xml but Java-based bean configuration. It means class annotated with this annotation is the place where beans are configured and will be a candidate for auto-detection. In this class, methods are annotated with #Bean which return an object of the class.
Example:
#Configuration
public class ConfigClass {
#Bean
public UserClass getObject() {
return new UserClass();
}
}
#Component - You cannot autowire (#Autowired) any class if it is not marked with #Component. It means when you want to autowire any class using annotation that class should be annotated with #Component.
Example:
#Component
public class A { .... }
public class B {
#Autowired
A a;
.....
.....
}
Spring Document for reference:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
#Component is imported by default with #Configuration. controllers, service, and repostory are children components (along with Configuration). They are also candidate for auto-detection.
I am extending on #reus's answer.
#Configuration Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
If you look at the #Configuration class, you will see that it is meta-annotated with #Component.
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Configuration
#Bean is enables us to define the dependency in any way we like, this is why the #Bean annotation goes above a methods and we manually create a bean object and return it from that method. #Component enables us to define a dependency quickly, that is why #Component goes above classes. We only inject it wherever we need.
Collectively these 3 points says that- to quickly define a bean, we can annotate the class with #Component. To define a bean as we like (support custom requirements), we can write the bean definition using #Bean inside a #Configuration annotated class.
Apart from the differences highlighted by reos.
The reason why #Configuration cannot be replaced by #Component is as below:
The difference is in how the inter bean dependency is handled.
Refer the link for a detailed explanation with example:
Difference between Configuration and Component

Resources