What are different ways to create Bean in Spring Boot?
- Using @Component over class – To create app specific bean
- Using @Configuration over class and @Bean over method – To create bean from third party class added as JAR dependency. You cannot add component in added JAR class files.
What is Dependency Injection?
Dependency injection is basically providing the objects that an object needs (its dependencies) instead of having it construct them itself.
What are Types of Dependency Injection?
- Constructor Injection – Dependency provided as parameter to constructor. This ensures Object is fully initialized upon creation and promoting immutability
- Setter Injection – Setter injection is having independent setter for each class attributes and calling setter method while initializing. Setter Injection allow more flexibility by allowing dependencies to be set or changed after object creation.
- Field Injection – Field injection is old method of injecting dependencies by specifying the @Autowired over field name. It works based on Java reflection and it is not recommended as it makes code more difficult to test
What are Stereotype Annotations?
Stereotype – idea of a particular type of person or thing.
Spring comes with 4 Stereotype annotations as below.
@Component is a generic stereotype for any Spring-managed component. @Repository, @Service, @Controller are specializations of @Component for more specific use cases (in the persistence, service, and presentation layers, respectively).
- @Component general-purpose stereotype annotation indicating that the class is a spring component.
- @Controller @Controller annotation indicates that a particular class serves the role of a controller. The dispatcher scans the classes annotated with @Controller and detects methods annotated with @RequestMapping annotations within them. We can use @RequestMapping on/in only those methods whose classes are annotated with @Controller
- @Repository
- @Service – @Service beans hold the business logic and call methods in the repository layer.
stereotype for persistence layer. @Repository’s job is to catch platform specific exceptions and re-throw them as one of Spring’s unified unchecked exception. By masking the platform specific exception to spring unified exception it helps 1.Providing higher level of Abstraction for User 2.By throwing unchecked exception it prevents user from adding unnecessary boiler plate for exception handling by means of try catch blocks
Note : Spring may add special functionalities for @Service, @Controller and @Repository based on their layering conventions.
How it is internally is all 3 are marked with @Component.@CompnentScan only scans @Component and does not look for @Controller, @Service and @Repository in general. They are scanned because they themselves are annotated with @Component.
@Component public @interface Service { …. } @Component public @interface Repository { …. } @Component public @interface Controller { … }
What happens when more than one bean of same type is found? What would be workaround?
Application would fail to start with error message Require Single bean but N beans found.
This could be addressed in two ways
- Using @Qualifier annotation
- Using @Primary annotation
@Qualifier annotation takes bean Id as value to uniquely identify a bean.
StudentController.java
public class StudentController{ . @Autowired public StudentController(@Qualifier("student") Person person){ . } }
Student.java
@Component public class Student implements Person{ . }
@Primary annotation works by giving first preference to bean which is marked with @Primary annotation. If two beans are marked with @Primary annotation then Spring boot throws an error. If both @Primary and @Qualifier annotation is used, then @Qualifier annotation takes preference.
@Primary vs @Qualifier Which one takes precedence?
@Qualifier takes precedence over @Primary annotation.
What does @Lazy annotation do?
Unlike the bean which are marked with @Component are loaded at startup when the app start, @Lazy annotation does the bean loading only when it is needed.
This can be Configured globally as well by specifying in application.properties as below. If your application has lot of components and because of this the app takes long time to start then its better to use this.
application.properties
spring.main.lazy-initialization=true
Note: If you use @Lazy annotation along with @Restcontroller it may lead to timeout issues.
Report.java
public interface Report { String generateReport(); }
PDFReport.java
@Primary @Component public class PDFReport implements Report{ public PDFReport() { System.out.println("Loaded PDFReport"); } @Override public String generateReport() { return "PDF Report"; } }
excelReport.java
@Component public class excelReport implements Report{ public excelReport() { System.out.println("Loading Excel Report"); } @Override public String generateReport() { return "Excel Report"; } }
textReport.java
@Component @Lazy public class textReport implements Report{ public textReport() { System.out.println("Loading textReport Report"); } @Override public String generateReport() { return "Text Report"; } }
GenerateReport.java
@RestController public class GenerateReport { private Report report; public GenerateReport(@Qualifier("excelReport") Report report){ this.report = report; } @GetMapping("/generateReport") public String generateReport(){ return "Printing report in "+ report.generateReport() + " format"; } }
Excel Report format would be printed as @Qualifier would take precedence
Output in Browser(http://localhost:8080/generateReport)
Loading Excel Report Loaded PDFReport Printing report in Excel Report format
What are different Bean Scopes?
Singleton – Only one bean for Container, served same bean for every access
Prototype – New bean for every access
Request – New bean for every request
Session – Only one bean for Session
Application – Only one bean for Application
Websocket –
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Checking Object based on Bean Scope – Singleton
excelReport bean with Singleton scope returning same bean every access
excelReport.java
@Component public class excelReport implements Report{ . . }
GenerateReport.java
@RestController public class GenerateReport { private Report report1; private Report report2; public GenerateReport(@Qualifier("excelReport") Report report1, @Qualifier("excelReport") Report report2){ this.report1 = report1; this.report2 = report2; } @GetMapping("/checkBean") public String checkBean(){ if(report1 == report2){ return "Bean are Same"; }else{ return "Bean are Different"; } } }
Output(http://localhost:8080/checkBean)
Bean are Same
Checking Object based on Bean Scope – Prototype
pdfReport bean with Prototype scope returning different bean on every access
PDFReport.java
@Primary @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class PDFReport implements Report{ . . }
GenerateReport.java
@RestController public class GenerateReport { private Report report1; private Report report2; public GenerateReport(Report report1, Report report2){ this.report1 = report1; this.report2 = report2; } @GetMapping("/checkBean") public String checkBean(){ if(report1 == report2){ return "Bean are Same"; }else{ return "Bean are Different"; } } }
Output(http://localhost:8080/checkBean)
Bean are Different
How to inject bean created using new Operator or Injecting Spring beans into non-managed objects
Objects for 3rd party JAR are created using @Configuration at class level and using @Bean at method level. This is one other way to create bean other than @Component as
we wont be able to change the source of 3rd party class files.
- Using @Configuration and @Bean annotation
- Using @Configurable refer here
- using AutowireCapableBeanFactory
Let take the below code
public class MyBean { @Autowired private AnotherBean anotherBean; } MyBean obj = new MyBean();
I have a class doStuff in which the obj of MyBean created using new operator needs to be injected. To do this use AutowireCapableBeanFactory and call autowireBean method with beanFactory reference.
private @Autowired AutowireCapableBeanFactory beanFactory; public void doStuff() { MyBean obj = new MyBean(); beanFactory.autowireBean(obj); //obj will now have its dependencies autowired. }
What is the Difference between @Inject and @Autowired in Spring Framework?
@Inject specified in javax.inject.Inject annotations is part of the Java CDI (Contexts and Dependency Injection) standard introduced in Java EE 6 (JSR-299). Spring has chosen to support using @Inject synonymously with their own @Autowired annotation.@Autowired is Spring’s own (legacy) annotation. @Inject is part of a new Java technology called CDI that defines a standard for dependency injection similar to Spring. In a Spring application, the two annotations work the same way as Spring has decided to support some JSR-299 annotations in addition to their own.
Use of the Following in Spring Framework?
@RequestMapping – All incoming requests are handled by the Dispatcher Servlet and it routes them through the Spring framework. When the Dispatcher Servlet receives a web request, it determines which controllers should handle the incoming request. Dispatcher Servlet initially scans all the classes that are annotated with the @Controller annotation. The dispatching process depends on the various @RequestMapping annotations declared in a controller class and its handler methods.The @RequestMapping annotation is used to map the web request onto a handler class (i.e. Controller) or a handler method and it can be used at the Method Level or the Class Level.
Example – for the URL http://localhost:8080/ProjectName/countryController/countries
@Controller @RequestMapping(value = "/countryController") public class CountryController { @RequestMapping(value = "/countries", method = RequestMethod.GET, headers = "Accept=application/json") public List getCountries() { // Some Business Logic }
Annotations | Equivalent |
---|---|
@GetMapping | @RequestMapping(method = RequestMethod.GET) |
@PostMapping | @RequestMapping(method = RequestMethod.POST) |
@PutMapping | @RequestMapping(method = RequestMethod.PUT) |
@DeleteMapping | @RequestMapping(method = RequestMethod.DELETE) |
@PatchMapping | @RequestMapping(method = RequestMethod.PATCH) |
@RequestParam – By using RequestParam we can get parameters to the method
@RequestMapping(value = "/display", method = RequestMethod.GET) public String showEmployeeForm(@RequestParam("empId") String empId) { // Some Business Logic }
@Pathvariable – @PathVariable is to obtain some placeholder from the URI
If empId and empName as parameters to the method showEmployeeForm() by using the @PathVariable annotation. For e.g.: /employee/display/101/Mux
empId = 101
empName = Mux
@Controller @RequestMapping(value = "/employee") public class EmployeeController { @RequestMapping(value = "/display/{empId}/{empName}") public ModelAndView showEmployeeForm(@PathVariable String empId, @PathVariable String empName) { // Some Business Logic } }
What is the Difference between @RequestParam vs @PathVariable?
@RequestParam annotation has following attributes
http://localhost:8080/springmvc/hello/101?param1=10¶m2=20
public String getDetails( @RequestParam(value="param1", required=true) String strParam1, @RequestParam(value="param2", required=false, defaultValue = "John") String strParam2){ ... }
@PathVariable is always considered required and cannot be null whereas @RequestParam could be null
@RequestParam annotation can specify default values if a query parameter is not present or empty by using a default Value attribute, provided the required attribute is false. . If a corresponding path segment is missing, Spring will result in a 404 Not Found error.
defaultValue | This is the default value as a fallback mechanism if request is not having the value or it is empty. i.e param1 |
name | Name of the parameter to bind i.e param1 |
required | Whether the parameter is mandatory or not. If it is true, failing to send that parameter will fail. i.e false |
value | This is an alias for the name attribute i.e param1 |
@PathVariable is to obtain some placeholder from the URI (Spring call it an URI Template) and @RequestParam is to obtain an parameter from the URI as well.@PathVariable annotation has only one attribute value for binding the request URI template. It is allowed to use the multiple @PathVariable annotation in the single method. But, ensure that no more than one method has the same pattern.Annotation which indicates that a method parameter should be bound to a name-value pair within a path segment. Supported for RequestMapping annotated handler methods.
localhost:8080/person/Tom;age=25;height=175 and Controller:
@GetMapping("/person/{name}") @ResponseBody public String person( @PathVariable("name") String name, @MatrixVariable("age") int age, @MatrixVariable("height") int height) { // ... }
How Spring will decide bean if there are multiple implementation of Same Instance?
In such case it would fail at start telling expected 1 bean but found n bean
We can use @Qualifier annotation where we can decide the bean to be loaded based on the beanId. beanId is always the component name with camel casing
public class GenerateReport { private Report report1; private Report report2; public GenerateReport(@Qualifier("excelReport") Report report1, Report report2){ this.report1 = report1; this.report2 = report2; } }
What BeanLife cycle methods are available?
@PostConstruct and @PreDestroy
@Component public class excelReport implements Report{ public excelReport() { System.out.println("Loading Excel Report"); } @Override public String generateReport() { return "Excel Report"; } @PreDestroy public void doCleanUpStuff(){ System.out.println("Disposing ExcelReport....: Prints when Server Stops"); } @PostConstruct public void doStartUpStuff(){ System.out.println("Completed Initialization ExcelReport...: Prints when Server Starts"); } }
Output – When Server Starts
Completed Initialization ExcelReport...: Prints when Server Starts
Output – When Server Stops
Disposing ExcelReport....: Prints when Server Stops
What is use of @RequestBody and @ResponseBody?
- @RequestBody and @ResponseBody used in controller to implement smart object serialization and deserialization. They help you avoid boilerplate code by extracting the logic of message conversion and making it an aspect. Other than that they help you support multiple formats for a single REST resource without duplication of code.
- If you annotate a method with @ResponseBody, spring will try to convert its return value and write it to the http response automatically.
- If you annotate a methods parameter with @RequestBody, spring will try to convert the content of the incoming request body to your parameter object on the fly.
What is @Transactional used for?
When Spring loads your bean definitions, and has been configured to look for @Transactional annotations, it will create these proxy objects around your actual bean. These proxy objects are instances of classes that are auto-generated at runtime. The default behaviour of these proxy objects when a method is invoked is just to invoke the same method on the “target” bean (i.e. your bean).
Refere here