Spring @Bean Annotation
June 22, 2019
Spring @Bean
annotation indicates that a method produces a bean to be managed by the Spring container. Spring @Bean
method can be created within @Configuration
and @Component
classes. The default scope of a bean is singleton. The @Bean
annotation can be used in conjunction with annotations such as @Scope
, @Lazy
, @DependsOn
, @Primary
etc.
Find the optional methods of
@Bean
annotation.
autowireCandidate: Boolean value to decide if this bean is a candidate for getting autowired into some other bean. Default is true. It is introduced in Spring 5.1.
initMethod: Method name to call on the bean instance during initialization. Default is no init method to be called on.
destroyMethod: Method name to call on the bean instance upon closing the application context. The method must have no arguments but can throw exceptions.
name: The name of this bean. Default bean name is method name.
value: Alias for name.
Here on this page we will discuss
@Bean
methods in detail with examples.
Contents
Technologies Used
Find the technologies being used in our example.1. Java 11
2. Spring 5.1.6.RELEASE
3. Spring Boot 2.1.4.RELEASE
@Bean within @Configuration Classes
We can create bean in@Configuration
class annotating @Bean
at methods. In @Configuration
class, create methods annotated with @Bean
and method needs to return object of a bean. In our example we have two classes BeanA
and BeanB
to be created as Spring bean. Find the code to use @Bean
annotation to create bean of these classes.
AppConfig.java
package com.concretepage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public BeanA getBeanA() { BeanA beanA = new BeanA(); beanA.setName("Bean A"); return beanA; } @Bean public BeanB getBeanB() { return new BeanB("Bean B"); } }
getBeanA
and second bean name is getBeanB
.
BeanA.java
package com.concretepage; public class BeanA { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.concretepage; public class BeanB { private String name; public BeanB(String name) { this.name = name; } public String getName() { return name; } }
@Autowired
annotation.
MySpringApp.java
package com.concretepage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MySpringApp { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); //BeanA beanA = ctx.getBean(BeanA.class); BeanA beanA = (BeanA) ctx.getBean("getBeanA"); System.out.println(beanA.getName()); BeanB beanB = ctx.getBean(BeanB.class); //BeanB beanB = (BeanB) ctx.getBean("getBeanB"); System.out.println(beanB.getName()); ctx.registerShutdownHook(); ctx.close(); } }
Bean A Bean B
Bean Names
We can change the default bean name usingname
attribute of @Bean
annotation. The default bean name is @Bean
annotated method name. When we assign bean name using name
attribute then default bean name will not be available. Multiple bean names can be assigned as an array for a single bean. To specify bean name we can use either name
or value
attribute. Find the example.
AppConfig.java
@Configuration public class AppConfig { @Bean("a1Bean") public BeanA getBeanA() { BeanA beanA = new BeanA(); beanA.setName("Bean A"); return beanA; } @Bean(name={"b1Bean", "b2Bean"}) public BeanB getBeanB() { return new BeanB("Bean B"); } }
a1Bean
and second bean name is b1Bean
and b2Bean
. We can access beans by their name as following.
MySpringApp.java
public class MySpringApp { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); BeanA beanA = (BeanA) ctx.getBean("a1Bean"); System.out.println(beanA.getName()); BeanB beanB1 = (BeanB) ctx.getBean("b1Bean"); System.out.println(beanB1.getName()); BeanB beanB2 = (BeanB) ctx.getBean("b2Bean"); System.out.println(beanB2.getName()); ctx.registerShutdownHook(); ctx.close(); } }
b1Bean
and b2Bean
will return same bean.
Output
Bean A Bean B Bean B
initMethod and destroyMethod
TheinitMethod
and destroyMethod
are the attributes of @Bean
annotation. In a bean we can have initialization and destroy method. initMethod
specifies any initialization method and destroyMethod
method specifies any destroy method. Initialization method will be called just after bean creation and destroy method will be called just before closing the application context. Find the example.
Work.java
package com.concretepage; public class Work { public void initWork() { System.out.println("--- Initializing Work ---"); } public void doWork() { System.out.println("-- Doing my Work ---"); } public void closeWork() { System.out.println("-- Closing Work ---"); } }
package com.concretepage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean(name="mywork", initMethod="initWork", destroyMethod="closeWork") public Work getWork() { return new Work(); } }
package com.concretepage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MySpringApp { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); Work work = (Work) ctx.getBean("mywork"); work.doWork(); ctx.registerShutdownHook(); ctx.close(); } }
--- Initializing Work --- -- Doing my Work --- -- Closing Work ---
Inter-Bean References
In a same configuration class, we can refer a@Bean
method in other @Bean
methods by calling them directly. Inner-bean references are guaranteed to respect scoping and AOP semantics. Find the example.
AppConfig.java
package com.concretepage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public Person getPerson() { return new Person("Mahesh"); } @Bean public School getSchool() { return new School(getPerson()); } }
package com.concretepage; public class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } }
package com.concretepage; public class School { private String schoolName = "ABC School"; private String principal; public School(Person person) { this.principal = person.getName(); } public String getSchoolName() { return schoolName; } public String getPrincipal() { return principal; } }
package com.concretepage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MySpringApp { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); School school = ctx.getBean(School.class); System.out.println(school.getPrincipal()); System.out.println(school.getSchoolName()); ctx.registerShutdownHook(); ctx.close(); } }
Mahesh ABC School
Using @Scope, @Lazy, @DependsOn and @Primary with @Bean
The@Bean
can be used with @Scope
, @Lazy
, @DependsOn
, @Primary
etc.
1. Using
@Scope
Default scope of a bean is
singleton
. We can change bean scope using @Scope
annotation. Bean scopes are prototype
, request
, session
etc. Find a sample example to change a bean scope to prototype
.
AppConfig.java
@Configuration public class AppConfig { @Bean @Scope("prototype") public BeanA getBeanA() { return new BeanA(); } }
2. Using
@Lazy
@Lazy
indicates whether a bean is to be lazily initialized.
AppConfig.java
@Configuration public class AppConfig { @Bean @Scope("prototype") @Lazy(true) public BeanA getBeanA() { return new BeanA(); } }
3. Using
@DependsOn
@DependsOn
specifies the beans on which the current bean depends.
AppConfig.java
@Configuration public class AppConfig { @Bean @Scope("prototype") @DependsOn("myBeanB") public BeanA getBeanA() { return new BeanA(); } @Bean("myBeanB") public BeanB getBeanB() { return new BeanB(); } }
4. Using
@Primary
@Primary
indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency.
AppConfig.java
@Configuration public class AppConfig { @Bean @Primary public BeanA getBeanA() { return new BeanA(); } ------ }
@Bean within @Component Classes
@Bean
methods can also be declared within classes annotated with @Component
annotation. In this case @Bean
methods are processed in lite mode. Here @Bean
methods will be treated as plain factory methods by the container and follow scoping and lifecycle callbacks properly.
The difference between
@Bean
methods of @Configuration
and @Component
classes is that the beans of @Component
classes do not support inner-bean references. In lite mode if a @Bean
method is invoking another bean method, it will be standard Java method invocation. Find the example to create @Bean
method within @Component
classes.
Utility.java
package com.concretepage; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Component public class Utility { public int addNumbers(int num1, int num2) { return num1 + num2; } @Bean public Square getSquare() { return new Square(); } }
package com.concretepage; public class Square { public int getSquare(int arm) { return arm * arm; } }
package com.concretepage; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.concretepage") public class AppConfig { }
package com.concretepage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MySpringApp { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); Square square = ctx.getBean(Square.class); int num = 10; System.out.println("Square of " + num + " = "+square.getSquare(10)); ctx.registerShutdownHook(); ctx.close(); } }
Square of 10 = 100