One of the most important annotations in spring is the @Bean annotation which is applied on a method to specify that it returns a bean to be managed by Spring context. Spring Bean annotation is usually declared in Configuration classes methods. This annotation is also a part of the spring core framework. So let’s understand @Bean Annotation with an example project.
Prerequisite:
- Spring @ComponentScan Annotation with Example
- Spring @Configuration Annotation with Example
Implementation: Project
Suppose we have already a Java project and all the Spring JAR files are imported into that project. Now let’s create a simple class named College and inside the class, we have a simple method. Below is the code for the College.java file and using the @Component and @ComponentScan annotation let’s create the bean of this college class. So we can write code for the College.java file something like this.
A. File: College.java
Java
// Java Program to Illustrate College Class package BeanAnnotation; // Importing required classes import org.springframework.stereotype.Component; // Annotation @Component ( "collegeBean" ) // Class public class College { // Method public void test() { // Print statement System.out.println( "Test College Method" ); } } |
Now let’s create a Configuration class named CollegeConfig. Below is the code for the CollegeConfig.java file
Configuration Class
Java
// Java Program to Illustrate Configuration Class package ComponetAnnotation; // Importing required classes import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; // Annotation @Configuration @ComponentScan (basePackages = "BeanAnnotation" ) // Class public class CollegeConfig { } |
But we do not want to use the @Component and @ComponentScan annotations to create the beans. Let’s discuss another way of doing the same task. So we are going to create the spring beans using the @Bean annotation. To create the College class bean using the @Bean annotation inside the configuration class we can write something like this inside our CollegeConfig.java file. Please refer to the comments for a better understanding.
@Bean // Here the method name is the // bean id/bean name public College collegeBean() { // Returns the College object return new College(); }
B. File: CollegeConfig.java
Java
// Java Program to Illustrate // Configuration of College Class package BeanAnnotation; // Importing required classes import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // Annotation @Configuration // Class public class CollegeConfig { // Creating College class Bean // using Bean annotation @Bean // Here the method name is the // bean id/bean name public College collegeBean() { // Returns the College class object return new College(); } } |
Note: Whenever you are using the @Bean annotation to create the bean you don’t need to use the @ComponentScan annotation inside your configuration class.
Now to check our application let’s create a main method inside our Main class. Below is the code for the Main.java file. Comments are added inside the code to understand the code in more detail.
C. Application Class
Java
// Java Program to Illustrate Application Class package BeanAnnotation; // Importing required classes import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; // Main(Application) Class public class Main { // Main driver method public static void main(String[] args) { // Using AnnotationConfigApplicationContext // instead of ClassPathXmlApplicationContext // because we are not using XML Configuration ApplicationContext context = new AnnotationConfigApplicationContext( CollegeConfig. class ); // Getting the bean College college = context.getBean( "collegeBean" , College. class ); // Invoking the method // inside main() method college.test(); } } |
Output:
Test College Method
Tip: Now let’s remove the @Bean annotation before the collegeBean() method and run our program again and you can see we are going to get the “NoSuchBeanDefinitionException” exception
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'collegeBean' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:863) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1160) at BeanAnnotation.Main.main(Main.java:15)
So the point is to make the collegeBean() method work like a bean you need to define the @Bean annotation before that particular method.
Giving Different Bean ID/Bean Name
Now the question is can we give a different Bean ID for this collegeBean() method? Yes, we can. We can modify our code something like this.
// Annotation @Bean(name = "myCollegeBean") // Class public College collegeBean() { return new College(); }
So whenever you want to test your application you have to also change your Main.java file to something like this.
D. Application Class
Java
// Java Program to Illustrate Application Class package BeanAnnotation; // Importing required classes import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; // Application(Main) class public class Main { // main driver method public static void main(String[] args) { // Using AnnotationConfigApplicationContext // instead of ClassPathXmlApplicationContext // because we are not using XML Configuration ApplicationContext context = new AnnotationConfigApplicationContext( CollegeConfig. class ); // Getting the bean College college = context.getBean( "myCollegeBean" , College. class ); // Invoking the method // inside main() method college.test(); } } |
Giving Multiple Names to the Same Bean
One more interesting thing is we can give multiple names to this particular collegeBean() method. So further we can modify our code something like this.
@Bean(name = {"myCollegeBean", "yourCollegeBean"}) public College collegeBean() { return new College(); }
Similarly, you need to modify your Main.java file during the execution of your application.
Dependency Injection with @Bean Annotation
Now let’s discuss another scenario. Suppose we have a dependency class named Principal inside our College class then what to do? So the scenario is like this. We have a class named Principal.java and we have defined a simple method inside this.
Example
Java
// Java Program to Illustrate Principal Class package BeanAnnotation; // Class public class Principal { // Method public void principalInfo() { // Print statement System.out.println( "Hi, I am your principal" ); } } |
And our College.class is something like this
Java
// Java Program to Illustrate College Class package BeanAnnotation; // Class public class College { // Class data member private Principal principal; // Method public void test() { principal.principalInfo(); // Print statement System.out.println( "Test College Method" ); } } |
So now we want to do the dependency injection. So we can do it in 2 ways as listed later implemented as shown below:
- Constructor Dependency Injection (CDI)
- Setter Dependency Injection (SDI)
Way 1: Constructor Dependency Injection (CDI)
In that case, first, let’s create a constructor inside the College class. So our modified College.java file is
A. College Class
Java
// Java Program to Illustrate College Class package BeanAnnotation; // Class public class College { private Principal principal; public College(Principal principal) { this .principal = principal; } public void test() { principal.principalInfo(); System.out.println( "Test College Method" ); } } |
Now come to the CollegeConfig.java file and the modified CollegeConfig.java is given below. Refer to the comments for better understanding.
B. Configuration Class
Java
// Java Program to Illustrate Configuration Class package BeanAnnotation; // Importing required classes import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // Annotation @Configuration public class CollegeConfig { // Creating the Bean for Principal Class @Bean public Principal principalBean() { return new Principal(); } @Bean public College collegeBean() { // Constructor Injection return new College(principalBean()); } } |
And finally Below is the code for the Main.java file.
C. Application Class
Java
// Java Program to Illustrate Application Class package BeanAnnotation; // Importing required classes import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; // Main class public class Main { // Main driver method public static void main(String[] args) { // Using AnnotationConfigApplicationContext // instead of ClassPathXmlApplicationContext // because we are not using XML Configuration ApplicationContext context = new AnnotationConfigApplicationContext( CollegeConfig. class ); // Getting the bean College college = context.getBean( "collegeBean" , College. class ); // Invoking the method // inside main() method college.test(); } } |
Output:
Hi, I am your principal Test College Method
Way 2: Setter Dependency Injection (SDI)
In that case, first, let’s create a setter method inside the College class. So our modified College.java file is as follows:
A. College Class
Java
// Java Program to Illustrate College Class package BeanAnnotation; // Class public class College { // Class data members private Principal principal; // Setter public void setPrincipal(Principal principal) { // this keywords refers to current instance itself this .principal = principal; } // Method public void test() { principal.principalInfo(); // Print statement System.out.println( "Test College Method" ); } } |
Now come to the CollegeConfig.java file and the modified CollegeConfig.java is given below as follows:
B. Configuration Class
Java
// Java Program to Illustrate Configuration Class package BeanAnnotation; // Importing required classes import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // Annotation @Configuration // Class public class CollegeConfig { // Creating the Bean for Principal Class @Bean public Principal principalBean() { return new Principal(); } @Bean public College collegeBean() { // Setter Injection College college = new College(); college.setPrincipal(principalBean()); return college; } } |
And finally Below is the code for the Main.java file.
C. Application Class
Java
// Java Program to Illustrate Application (Main) Class package BeanAnnotation; // Importing required classes import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; // Application (Main) class public class Main { // Main driver method public static void main(String[] args) { // Using AnnotationConfigApplicationContext // instead of ClassPathXmlApplicationContext // because we are not using XML Configuration ApplicationContext context = new AnnotationConfigApplicationContext( CollegeConfig. class ); // Getting the bean College college = context.getBean( "collegeBean" , College. class ); // Invoking the method // inside main() method college.test(); } } |
Output:
Hi, I am your principal Test College Method