Pages

Tuesday, April 21, 2020

Spring Boot @Bean - Creating Bean In Spring

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 creation in spring boot


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

[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.