16.1 Overview
In previous chapters we discussed annotations and XML based configurations. Spring also supports Java based configuration where we can define an application context, bean definition as annotation.
In this chapter, we will discuss following annotations
- @Configuration
- @Bean
- @Scope
16.2 @Configuration
The @Configuration annotation applies only at a class level. Once done that class acts as a spring bean configuration file. Class annotated with @Configuration must have a default constructor.
Refer below sample structure
@Configuration public class AppConfiguration { public AppConfiguration() { } }
16.3 @Bean
@Bean annotation is applied to a method of a class annotated with @Configuration. One method annotated with @Bean is equivalent to one bean definition in spring bean definition.
Refer below sample structure
@Configuration public class AppConfiguration { public AppConfiguration() { } @Bean public Student student() { return new Student(); } }
Above class is equivalent of defining a student bean
<bean id=”student” class=”Student” />
16.4 Dependency Injection
The calling @Bean annotated bean from another @Bean annotated method can inject the beans. For example, if Hostel bean has a dependency on Student object, then following structure can be used.
@Configuration public class AppConfiguration { Public AppConfiguration() { } @Bean public Student student() { return new Student(); } @Bean public Hostel hostel() { return new Hostel(student()); } }
Above configuration is equivalent to
<bean id=”student” class=”Student” /> <bean id=”hostel” class=”Hostel” > <constructor-arg ref=”student” /> </bean>
16.5 Lifecycle Callbacks
In earlier chapters we discussed that we can define and configure custom initialization and destroy methods using init-method and destroy-method attributes of a bean.
Similarly @Bean annotation supports initMethod and destroyMethod attributes to configure the name of callback methods .
@Configuration public class AppConfiguration { public AppConfiguration() { } @Bean(initMethod="init" ,destroyMethod="destroy") public Student student() { return new Student(); } }
Above code is equivalent to below configuration and Student class will have init() and destroy() methods defined.
<bean id=”student” class=”Student” init-method="init" destroy-method="destroy"/>
16.6 Bean name configuration
We can pass the bean name of the bean in the name attribute of @Bean annotation. By default the name of the method becomes a bean name.
@Configuration public class AppConfiguration { public AppConfiguration() { } @Bean(name="studentBean") public Student getStudent() { return new Student(); } @Bean public Hostel hostel() { return new Hostel(); } }
Above code is equivalent to
<bean id=”studentBean” class=”Student” /> <bean id=”hostel” class=”Hostel”/>
16.7 @Scope
@Scope annotation is defined on a method and is used to configure the scope of a bean. By default scope is singleton so if any method annotated with @Bean configuration is not annotated with @Scope will be of singleton scope.
Possible value can be passed in @Scope annotation
- singleton
- prototype
- request
- session
- globalSession
@Configuration public class AppConfiguration { public AppConfiguration() { } @Bean @Scope("prototype") public Student student() { return new Student(); } @Bean public Hostel hostel() { return new Hostel(); } }
In above code student bean is defined as prototype where as hostel bean will be singleton as singleton is a default scope.
Note: Though hostel method returns new Hostel() does not mean that a new hostel instance will be returned always.
16.8AnnotationContextApplicationContext
Spring provides AnnotationContextApplicationContext class which takes @Configuration annotated classes to load the class.
Below code snippet will load the AppConfiguration class
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
If multiple @Configuration classes need to be loaded then register and refresh methods need to be called (refer below code snippet)
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfiguration.class); context.refresh();
16.9Example
Lets write an example to demonstrate the above topics.
a. Student class
publicclass Student { private String name ; public String getName() { return name; } publicvoid setName(String name) { this.name = name; } }
publicclass Hostel { private Student student; public Hostel(Student student) { this.student= student; } publicvoid init() { System.out.println("init method called !!!"); } @Override public String toString() { return "Hostel [student=" + student.getName() + "]"; } }
c. AppConfiguration class
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration publicclass AppConfiguration { public AppConfiguration() { } @Bean(name="student") @Scope("prototype") public Student getStudent() { Student student = new Student(); student.setName("Student A"); return student; } @Bean( initMethod="init") public Hostel hostel() { returnnew Hostel(getStudent()); } }
d. TestAnnotationConfiguration class
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.AbstractApplicationContext; public class TestAnnotationConfiguration { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfiguration.class); context.refresh(); Student studentA = (Student)context.getBean("student"); Student studentB = (Student)context.getBean("student"); System.out.println("Is student bean is singleton? " + (studentA==studentB)); Hostel hostel1 = (Hostel)context.getBean("hostel"); Hostel hostel2 = (Hostel)context.getBean("hostel"); System.out.println(hostel1); System.out.println(hostel2); System.out.println("Is Hostel bean is singleton? " + (hostel1==hostel2)); ((AbstractApplicationContext)context).registerShutdownHook();; } }
- Run TestAnnotationConfiguration class. You will see below output.
- Init method gets called only once because Hostel bean is a singleton
- Hostel bean displays the student name which means student object is injected properly
- StudentA and StudentB beans are not singleton because Student class is annotated with @Scope( “ prototype “)