Spring Boot Bean Creation
1. Introduction
In this tutorial, We'll learn how to Create Bean in Spring and Spring Boot frameworks. We'll look at @Bean annotation along with its scopes and Method Injection examples.
@Bean annotation is introduced in Spring framework to avoid XML level configurations. This can be used in Spring Boot application.
@Bean and @Component are almost are same and used to create the bean but seems like same as produces same as a result.
@Bean and @Component are almost are same and used to create the bean but seems like same as produces same as a result.
2. Spring Boot @Bean Creation Syntax
In Spring Boot, @Bean is a method level annotation and should not be used in any class. And also this annotation tells that it returns a bean that is to be managed by the spring container and registered with spring application context or BeanFactory.
OrderInfo.class
[class OrderInfo{
@Bean
public Customer getCustomer(){
return new Customer();
}
}]
This method returns a bean of the Customer.
3. Spring Boot @Bean Attributes
@Bean annotation is equaled to the <bean> tag and almost supports all types of attributes of <bean> tag.
Supported attributes
autowire
autowireCandidate
initMethod
destroyMethod
4. Spring Boot @Bean Create - Example
Now, You'll be seeing now how to use @Bean annotation to create the objects at runtime and those will be managed by the spring container.
The following is an example for creating bean in multiple ways with different attributes.
Produce.java
[package com.javaprogramto.bean.create.beancreation;
public interface Produce {
String generate();
}]
BeanCreations.java
We will be using CommandLineRunner for testing purpose. Because we no need to create and expose a rest or web application.
Once we run SpringBootApplication then it will execute run() method of CommandLineRunner interface.
[package com.javaprogramto.bean.create.beancreation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Configuration
public class BeanCreations implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
Produce produce1;
@Autowired
Produce produce2;
@Bean
public Produce getProduce() {
return () -> "Produced Value";
}
@Override
public void run(String... args) throws Exception {
logger.info(" produced value 1: hash " + produce1.hashCode());
logger.info(" produced value 1: " + produce1.generate());
logger.info("---------------------------------------");
logger.info(" produced value 2: hash " + produce2.hashCode());
logger.info(" produced value 2: " + produce2.generate());
}
}]
Here, Created a method with @Bean annotation that produces an object for Produce interface implementation. To make the example simple, Created all beans and autowired in the single class.
Injected two beans for the same type and printed the hashcode and its values to see whether the same object is returned for multiple objects creation.
Output:
Now, let us start the main() method SpringBootApplication. Next, Look at the output and observe the hashcode for the two objects. Both objects are having the same hashcode that means container created a single object that is referenced to produce1 and produce2.
[ . ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-04-21 21:23:35.716 INFO 23027 --- [ main] c.j.b.c.b.BeanCreationApplication : Starting BeanCreationApplication on -Pro-2.local with PID 23027 (/Users/venkateshn/Documents/VenkY/blog/workspace/untitled folder/bean-creation/target/classes started by venkateshn in /Users/venkateshn/Documents/VenkY/blog/workspace/untitled folder/bean-creation)
2020-04-21 21:23:35.720 INFO 23027 --- [ main] c.j.b.c.b.BeanCreationApplication : No active profile set, falling back to default profiles: default
2020-04-21 21:23:36.151 INFO 23027 --- [ main] c.j.b.c.b.BeanCreationApplication : Started BeanCreationApplication in 0.727 seconds (JVM running for 1.145)
2020-04-21 21:23:36.152 INFO 23027 --- [ main] c.j.b.create.beancreation.BeanCreations : produced value 1: hash 1142347343
2020-04-21 21:23:36.152 INFO 23027 --- [ main] c.j.b.create.beancreation.BeanCreations : produced value 1: Produced Value
2020-04-21 21:23:36.152 INFO 23027 --- [ main] c.j.b.create.beancreation.BeanCreations : ---------------------------------------
2020-04-21 21:23:36.152 INFO 23027 --- [ main] c.j.b.create.beancreation.BeanCreations : produced value 2: hash 1142347343
2020-04-21 21:23:36.152 INFO 23027 --- [ main] c.j.b.create.beancreation.BeanCreations : produced value 2: Produced Value ]
5. Spring Boot @Bean Scopes Examples
in addition to the @Bean annotation, We can another annotation for its scope. @Scope annotation is to define the scope of the bean. Scope values can be prototype, singleton and others. But default is singleton as seen in the above example.
below example to create prototype bean that creates a different objects. This can be tested by seeing the created objects hashcode.
ProduceImpl.java
ProduceImpl.java
[class ProduceImpl implements Produce {
@Override
public String generate() {
// TODO Auto-generated method stub
return "Produce object " + Math.random();
}
}]
BeanScopes.java
[@Configuration
public class BeanScopes {
@Bean(name = "p1")
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Produce getProduceBean() {
return new ProduceImpl();
}
}]
BeanScopesBody.java
[@Configuration
public class BeanScopesBody implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
@Qualifier("p1")
private Produce p1;
@Autowired
@Qualifier("p1")
private Produce p2;
@Override
public void run(String... args) throws Exception {
logger.info(" produced value 1: hash " + p1.hashCode());
logger.info(" produced value 2: hash " + p2.hashCode());
}
}]
Output:
[2020-04-21 22:00:59.246 INFO 24606 --- [ main] pesBody$$EnhancerBySpringCGLIB$$5ae3935e : produced value 1: hash 1052253947
2020-04-21 22:00:59.246 INFO 24606 --- [ main] pesBody$$EnhancerBySpringCGLIB$$5ae3935e : produced value 2: hash 451460284]
6. Bean Creation with Method injection using @Bean
There is another way to create a mean using method injection technique. But, This is an advanced technique but rarely used.
[package com.javaprogramto.bean.create.beancreation;
import org.springframework.context.annotation.Bean;
@Component
public class MethodInjection {
@Bean("p3")
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Produce methodInjection() {
return new Produce() {
@Override
public String generate() {
return "" + Math.random();
}
};
}
}]
Finally, This approach mainly used in XML configuration where we want to inject prototype bean as a dependency to a Singleton bean.
here, MethodInjection is a singleton and it has a dependency to prototype bean Produce.
[package com.javaprogramto.bean.create.beancreation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MethodInjectionBody implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MethodInjection methodInjection1;
@Autowired
private MethodInjection methodInjection2;
@Override
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
logger.info("Demo for method injection");
logger.info("methodInjection1 hashcode : " + methodInjection1.hashCode());
logger.info("methodInjection2 hashcode : " + methodInjection2.hashCode());
logger.info("both objects hashcodes are same. So, MethodInjection is singleton");
logger.info("methodInjection1 hashcode : " + methodInjection1.hashCode());
logger.info("methodInjection1 produce hashcode : " + methodInjection1.methodInjection().hashCode());
logger.info("methodInjection1 produce hashcode : " + methodInjection1.methodInjection().hashCode());
logger.info("methodInjection1 produce hashcode : " + methodInjection1.methodInjection().hashCode());
logger.info("methodInjection2 hashcode : " + methodInjection2.hashCode());
logger.info("methodInjection2 produce hashcode : " + methodInjection2.methodInjection().hashCode());
logger.info("methodInjection2 produce hashcode : " + methodInjection2.methodInjection().hashCode());
logger.info("methodInjection2 produce hashcode : " + methodInjection2.methodInjection().hashCode());
}
}]
Output:
Observe hashcodes of produce object carefully and all are printed as different. So, it is working as a singleton to prototype bean dependency.
[2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : Demo for method injection
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection1 hashcode : 417557780
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection2 hashcode : 417557780
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : both objects hascodes are same. So, MethodInjection is singleton
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection1 hashcode : 417557780
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection1 produce hashcode : 1350751778
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection1 produce hashcode : 332699949
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection1 produce hashcode : 808417649
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection2 hashcode : 417557780
2020-04-21 22:28:47.264 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection2 produce hashcode : 858204589
2020-04-21 22:28:47.265 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection2 produce hashcode : 1976752685
2020-04-21 22:28:47.265 INFO 25798 --- [ main] ionBody$$EnhancerBySpringCGLIB$$d7627141 : methodInjection2 produce hashcode : 1115170891]
7. Conclusion
In conclusion to this article, We've seen how to create a bean using @Bean annotation and its attributes. How to set the scope for a bean and example on method injection.
And also finally, Injecting prototype bean into a singleton bean.
As usual code on GitHub.
- [accordion]
- BeanCreationApplication.java
package com.javaprogramto.bean.create.beancreation; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class BeanCreationApplication { public static void main(String[] args) { SpringApplication.run(BeanCreationApplication.class, args); } }
- BeanCreations.java
package com.javaprogramto.bean.create.beancreation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class BeanCreations implements CommandLineRunner { Logger logger = LoggerFactory.getLogger(getClass()); @Autowired @Qualifier("p2") Produce produce1; @Autowired @Qualifier("p2") Produce produce2; @Bean("p2") public Produce getProduce() { return () -> "Produced Value"; } @Override public void run(String... args) throws Exception { logger.info(" produced value 1: hash " + produce1.hashCode()); logger.info(" produced value 1: " + produce1.generate()); logger.info("---------------------------------------"); logger.info(" produced value 2: hash " + produce2.hashCode()); logger.info(" produced value 2: " + produce2.generate()); } }
- BeanScopes.java
package com.javaprogramto.bean.create.beancreation; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration public class BeanScopes { @Bean(name = "p1") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Produce getProduceBean() { return new ProduceImpl(); } } class ProduceImpl implements Produce { @Override public String generate() { // TODO Auto-generated method stub return "Produce object " + Math.random(); } }
- BeanScopesBody.java
package com.javaprogramto.bean.create.beancreation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Configuration; @Configuration public class BeanScopesBody implements CommandLineRunner { Logger logger = LoggerFactory.getLogger(getClass()); @Autowired @Qualifier("p1") private Produce p1; @Autowired @Qualifier("p1") private Produce p2; @Override public void run(String... args) throws Exception { logger.info(" produced value 1: hash " + p1.hashCode()); logger.info(" produced value 2: hash " + p2.hashCode()); } }
- MethodInjection.java
package com.javaprogramto.bean.create.beancreation; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component public class MethodInjection { @Bean("p3") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Produce methodInjection() { return new Produce() { @Override public String generate() { return "" + Math.random(); } }; } }
- MethodInjectionBody.java
package com.javaprogramto.bean.create.beancreation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Configuration; @Configuration public class MethodInjectionBody implements CommandLineRunner { Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private MethodInjection methodInjection1; @Autowired private MethodInjection methodInjection2; @Override public void run(String... args) throws Exception { // TODO Auto-generated method stub logger.info("Demo for method injection"); logger.info("methodInjection1 hashcode : " + methodInjection1.hashCode()); logger.info("methodInjection2 hashcode : " + methodInjection2.hashCode()); logger.info("both objects hascodes are same. So, MethodInjection is singleton"); logger.info("methodInjection1 hashcode : " + methodInjection1.hashCode()); logger.info("methodInjection1 produce hashcode : " + methodInjection1.methodInjection().hashCode()); logger.info("methodInjection1 produce hashcode : " + methodInjection1.methodInjection().hashCode()); logger.info("methodInjection1 produce hashcode : " + methodInjection1.methodInjection().hashCode()); logger.info("methodInjection2 hashcode : " + methodInjection2.hashCode()); logger.info("methodInjection2 produce hashcode : " + methodInjection2.methodInjection().hashCode()); logger.info("methodInjection2 produce hashcode : " + methodInjection2.methodInjection().hashCode()); logger.info("methodInjection2 produce hashcode : " + methodInjection2.methodInjection().hashCode()); } }
- Produce.java
package com.javaprogramto.bean.create.beancreation; public interface Produce { String generate(); }
[lock]
No comments:
Post a Comment
Please do not add any spam links in the comments section.