Spring @Configuration annotation
In this article, we will take a look at @Configuration
annotation in spring framework and spring boot.
We will be covering what this annotation is, how to use it, and why it should be used.
Spring
@Configuration
annotation is used to indicate that a class contains bean definitions.These bean definitions can be used by the Spring container to create and configure beans.
It can be used on any class, but it is typically used on classes that are used to configure Spring beans.
This annotation can be used either with Java-based configuration or with XML-based configuration.
A class annotated with @Configuration
contains one or more methods that return objects or beans. These methods are themselves annotated with @Bean
.
Spring docs for @Configuration
state,
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.
A class with @Configuration contains methods that return spring beans. These methods are annotated with @Bean
annotation.
A benefit of @Configuration
is that classes with this annotation allow you to keep all of your bean definitions in a single place. This can be especially helpful if you have a large application with many different types of beans
Spring @Configuration example
Below is an example of Spring @Configuration
annotation which contains a method to create an object of User
.
@Configuration public class AppConfiguration { @Bean public User getUser() { return new User(); } }
Below is the User
class whose object is created in getUser()
method
package com.codippa; public class User { public User() { System.out.println("Creating user"); } }
To get a User
object from Spring application context, use below code
AnnotationConfigApplicationContext c = new AnnotationConfigApplicationContext(); c.register(AppConfiguration.class); c.refresh(); User user = c.getBean(User.class);
When this code is executed, you will see below message printed on the console
Creating user
@Bean
are called immediately after refresh()
, not when getBean()
is called.Notice that the class annotated with @Configuration
is registered inside the application context with its register()
method.
If you do not register it, then User will not be registered as a bean and Spring will not be able to find it, which is evident from the below error.
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.codippa.User’ available
Also, note that you should call refresh()
on application context after registering Configuration class with it.
refresh()
reloads the persistent configuration into Spring application context. If you do not call refresh()
, then you get
Exception in thread “main” java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@42607a4f has not been refreshed yet
If your application is a web application, then you should use AnnotationConfigWebApplicationContext
instead of AnnotationConfigApplicationContext
.
Instead of writing above code to register @Configuration
classes, you can also register them with XML configuration with following lines
<beans> <context:annotation-config/> <bean class="com.codippa.AppConfiguration"/> </beans>
Also, if you are using Spring boot, then there is no need to invoke register()
in order to register @Configuration
classes, since they are automatically registered by Spring at application startup.
That is, if you application starts like this
SpringApplication.run(DemoApplication.class, args);
then all the above steps are NOT required.
All
@Bean
methods defined in @Configuration
class are executed as the spring container starts. This means that @Bean
methods have eager initialization.However, this behavior can be controlled with
@Lazy
annotation so that beans are initialized only when required. Example,@Configuration @Lazy public class ConfigurationDemo { @Bean public BeanA beanA() { return new BeanA(); } }
@Bean
method will not be called on application startup. It will be called when BeanA
needs to be initialized.
@Lazy
can also be used over individual @Bean
methods as shown below
@Configuration public class ConfigurationDemo { @Bean public BeanA beanA() { return new BeanA(); } @Bean @Lazy public BeanC beanC() { return new BeanC(); } }
In this case, BeanA
will be eagerly initialized while BeanC
will be lazily initialized on demand.
@Configuration with @Profile
Similar to @Lazy
, beans can be loaded on the basis of active profiles using @Profile
annotation in conjunction with @Configuration.
@Profile
can be applied at the class level so that all @Bean methods will be invoked if a particular profile is active as shown below.
@Configuration @Profile("prod") public class ConfigurationDemo { @Bean public DataSource getDataSource() { return new DataSource(); } }
In this case, getDataSource()
will be invoked only when active profile is “prod”.
@Profile
can be applied at individual @Bean
methods so that they are invoked according to the active profile. Example,
@Configuration public class ConfigurationDemo { @Bean @Profile("prod") public DataSource getProdDataSource() { return new ProdDataSource(); } @Bean @Profile("staging") public DataSource getStagedDataSource() { return new StagedDataSource(); } }
In above example, @Bean
method corresponding to the active profile will be invoked.
Needless to say, you can combine @Configuration
, @Lazy
and @Profile
annotations to load beans as they are required(lazily), according to the active profile.
Even if you remove
@Configuration
from AppConfiguration
class in above example, then also it will work. That is, you will get an instance of User
from application context.
Then what is the use of @Configuration
?
@Configuration
ensures that the instances of objects created with @Bean
are singleton. That is, even if getUser()
is called multiple times, the object of User
will be created only once.
But if @Configuration
is removed, each call to getUser()
will create a new object. Consider below example.
Create a new class UserDetail
, which accepts an argument of type User
package com.codippa; public class UserDetail { public UserDetail(User u) { System.out.println("Creating user detail"); } }
Now, add a new method to AppConfiguration
that creates an instance of UserDetail
.
// @Configuration public class AppConfiguration { @Bean public User getUser() { return new User(); } @Bean public UserDetail detail() { return new UserDetail(getUser()); } }
Notice that @Configuration
annotation is commented. Now, when you run this code
AnnotationConfigApplicationContext c = new AnnotationConfigApplicationContext(); c.register(AppConfiguration.class); c.refresh();
Below logs are printed on the console
20:39:05.813 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory – Creating shared instance of singleton bean ‘getUser’
Creating user
20:39:05.861 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory – Creating shared instance of singleton bean ‘detail’
Creating user
Creating user detail
As you can see, User
bean is created twice. One, when getUser()
is called for @Bean
and second, when it is called from detail()
method.
@Configuration
annotation in Spring.Hope the article was informative.