Spring @Bean Annotation

By Arvind Rai, 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.

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");
	}	
} 
The default bean name will be method name. It means first bean name is 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;
	}
} 
BeanB.java
package com.concretepage;
public class BeanB {
	private String name;
	public BeanB(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
} 
A bean can be accessed by bean class or bean name or can be injected in component using @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();
	}
} 
Output
Bean A
Bean B 

Bean Names

We can change the default bean name using name 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");
	}	
}
The first bean name is 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

The initMethod 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 ---");		
	}
} 
AppConfig.java
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();
	}	
}
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);
		Work work = (Work) ctx.getBean("mywork");		
                work.doWork();		
		ctx.registerShutdownHook();
		ctx.close();
	}
} 
Output
--- 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());
	}		
} 
Person.java
package com.concretepage;
public class Person {
	private String name;
	public Person(String name) {
        this.name = name;
	}
	public String getName() {
		return name;
	}
} 
School.java
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;
	}
}
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);
		School school = ctx.getBean(School.class);
		System.out.println(school.getPrincipal());
		System.out.println(school.getSchoolName());
		ctx.registerShutdownHook();
		ctx.close();
	}
}
Output
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();
	}
} 
Square.java
package com.concretepage;
public class Square {
	public int getSquare(int arm) {
		return arm * arm;
	}
} 
AppConfig.java
package com.concretepage;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.concretepage")
public class AppConfig {

} 
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);
		Square square = ctx.getBean(Square.class);
		int num = 10;
		System.out.println("Square of " + num + " = "+square.getSquare(10));
		ctx.registerShutdownHook();
		ctx.close();
	}
}
Output
Square of 10 = 100 

Reference

Spring Doc: @Bean
POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us