How Spring Boot Works?
-Ashmeet Kaur

How Spring Boot Works?

In this article , We will know how spring boot works

What are Beans? Beans are the object that are created by Spring itself .

Advantages of Beans ??The lifecycle of the object is maintained by Spring . ??There is no need to worry about creation and deletion of object because that is solely managed by Spring.

What is Inversion of Control ? There is no need to create or manage the object now because that will be solely managed by Spring.

Will the spring create objects for Every Class? ??No , The spring will not create object by itself for every class.For creating an object,We have to mention @Component either directly or indirectly.

To understand it better Lets Consider this two Scenarios: Case I: Suppose a annotation @Component is directly mentioned, then in this Case we know that object of this class has been created . Case II: Suppose Now some other @RestController is mentioned in Class. then we have to check from where this RestController is extending from .If this is extending from @Component then the object of this Class is created and managed by Spring.Please refer the below mentioned snippet for more clearification.

????????????Snippet-1???????????????

//This is a DemoController Class . Here Annotation is iOneDIY Educationontroller
 

package com.example.demospring

import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
};
        


????????????Snippet-2???????????????

/*Here we Can see that the RestController is implemented from Controller*/


package org.springframework.web.bind.annotation

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
;

        



????????????Snippet-3???????????????

/*Here the Controller is implemented by Component*/


package org.springframework.stereotype

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}
;        


??Now Lets run this see the logs whether the object of this DemoController is getting or not.


????????????Snippet-4???????????????

/*Here its mentioned that shared instanceros ,it means that this object will be shared across class and singelton means that there will be only one object that is created*/

main] o.s.b.f.s.DefaultListableBeanFactory? ? ?: Creating shared instance of singleton bean 'demoController'        


Can We create Object of the Singleton Class? ??Yes, We can create as many object as we want but we have to manage those objects. These object will not be managed by Spring.The object that will be created by Spring will be stored in spring Container and can be easily retrieved .

How can we invoke a function through API? Step I: Lets make a Class Demo.


????????????Snippet-5???????????????

//This is the class Demo

@Component
public class Demo
{
    private int id;
    private String value;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
t        

Step II:


????????????Snippet-6???????????????


/*Here we make a function getDemo() that will be called when we call this endpoint /sample*/


@RestController
public class DemoController {

    public  static Logger logger= LoggerFactory.getLogger(DemoController.class);
    DemoController()
    {
        logger.info("Creating object {}",this);
    }

    @GetMapping("/sample")
    public Demo getDemo()
    {
        Demo demo=new Demo();
        logger.info("Demo object in sample API {}",demo);
        return demo;
    }
}
        

Step III: Now lets call this endoint "https://localhost:8080/sample"

No alt text provided for this image
Fig :1

?See in the above Fig:1, the client is calling this api/endpoint "/sample" by using the server ip "https://localhost:8080/sample" where port is 8080.The request goes to the server.Now the servelet routes the request to the class and call the method where this api is mentioned and sent response back to the client.But in the above Scenario , We are creating object on our own and managing by using new keyword.Now Let invoke the method by using Spring.

Invoking method by using Spring ? Here we will be invoking method by using spring but before invoking lets get familier with few things. a).@Autowired-This Autowired picks the reference of this object from the IOC container.


????????????Snippet-7???????????????


/*Here in this code we have used @Autowired.So this annotation picks the reference of the Demo Class and uses it without creating the object using new keyword.Spring is injecting the object of demo in the DemoController Class */
 

????????@RestController
public class DemoController {

    public  static Logger logger= LoggerFactory.getLogger(DemoController.class);
    DemoController()
    {
        logger.info("Creating object {}",this);
    }

    @Autowired
    Demo demo;

    @GetMapping("/sample")
    public Demo getDemo()
    {
        logger.info("Demo object in sample API {}",demo);
        return demo;
    }
}
        

We can give different annotation so that the reader can understand what class is exactly doing .Suppose if there is some database connectivity in the class . We can keep @Repository instead of @Component although in both the cases, Object will be created but the readers can know that this class is acting like Repository.

If we want logs for the spring package: ?logging.level.org.springframework=debug;

What if in Snippet-7 we put @Component in place of @RestController? I kept @Component in place of @RestController. Refer Snippet-8


????????????Snippet-8???????????????

????????@Component
public class DemoController {

    public  static Logger logger= LoggerFactory.getLogger(DemoController.class);
    DemoController()
    {
        logger.info("Creating object {}",this);
    }

    @Autowired
    Demo demo;

    @GetMapping("/sample")
    public Demo getDemo()
    {
     //   Demo demo=new Demo();
        logger.info("Demo object in sample API {}",demo);
        return demo;
    }
}t        

Output-For the same Api , we are getting 404

No alt text provided for this image
Fig-2

Why are we getting different output for fig:1 and fig:2? We have defined @GetMapping in DemoController Class.In snippet 7,we mentioned @RestController but in snippet 8 ,we mentioned @Component. So now question arises why we are getting different output.

To understand it better, please go through the below mentioned points. ?The Client(Browser) sends the request to the server. ?The dispatcher servelet calls the method Simple url handler mapping handles the request and send to the Classes only which maps to Controller directly or indirectly. ?So if the class contains @Component , the dispactcher will neglect the classes.It will only consider the classes which have @Controller/Restcontroller or any annotion which are having parent as controller.

What is @RequestMapping annotation? Suppose we have two apis . The two apis have something common for example "v1/sample" and "v1/postsample". so here we have "v1" as common . so instead of mentioning in @GetMapping(/v1/sample).We can write @RequestMapping("/v1").

To understand it better please refer snippet-9


????????????Snippet-9???????????????

 @Controller

??????@RequestMapping("/v1")

public class DemoController {

    public  static Logger logger= LoggerFactory.getLogger(DemoController.class);
    DemoController()
    {
        logger.info("Creating object {}",this);
    }

    @Autowired
    Demo demo;

    @GetMapping("/sample")
    public Demo getDemo()
    {
     //   Demo demo=new Demo();
        logger.info("Demo object in sample API {}",demo);
        return demo;
    }
    @PostMapping("/postsample")
    public Demo postDemo()
    {
        logger.info("demo object {}",demo);
        return demo;
    }
}
        

Output-:

No alt text provided for this image
fig-3

In fig 3,We should not be getting Error as we have used @Controller.But here the question arises that why are we getting Error.To understand this better , We have to understand the differnce betwen Controller and RestController.

What is the Difference between @RestController and @Controller? RestController is having Responsebody which converts the java into json format and passes to the client.In Case of Controller, It doesnot have Response body so its throws error.If in case of Controller Annotation we have to explicitly mention @Responsebody for displaying content on browser.

In Case of @Controller, the output will come ,if we mention @Responsebody


????????????Snippet-10??????????????


@GetMapping("/sample")
@ResponseBody
public Demo getDemo()
{
 //   Demo demo=new Demo();
    logger.info("Demo object in sample API {}",demo);
    return demo;
})        

In Case of @RestController,There is no need to mention @ResponseBody explicitly.it will show correct output.



????????????Snippet-11??????????????


@GetMapping("/sample")
public Demo getDemo()
{
 //   Demo demo=new Demo();
    logger.info("Demo object in sample API {}",demo);
    return demo;
})        

?Just Note that ,the client will accept the response in some format so server has to response in the same format then only the client will accept , otherwise it will throw error.

There are two ways of injecting the dependency. 1).Field Injection 2).Constructor

1).Field Injection-Field injection is autowiring as Snippet-7. 2).Constructor-if we remove autowired, it will be able to create the object , but it will not be able to inject the dependency.if we dont want to inject the dependency as a field we can inject it as a constructor also.



????????????Snippet-12??????????????

@Controller
@RequestMapping("/v1")
public class DemoController {

    public  static Logger logger= LoggerFactory.getLogger(DemoController.class);
    Demo demo;

????????public DemoController(Demo demo)
    {
        this.demo=demo;
        logger.info("Creating object {}",this);
    }


 /*   @Autowired
    Demo demo;*/



    @GetMapping("/sample")
    @ResponseBody
    public Demo getDemo()
    {
     //   Demo demo=new Demo();
        logger.info("Demo object in sample API {}",demo);
        return demo;
    }
    @PostMapping("/sampler")
    @ResponseBody
    public Demo postDemo()
    {
        logger.info("demo object {}",demo);
        return demo;
    }
}
        

We know that DemoController is having @Controller so technically the spring creates the object of this class and save it in IOC container. But while spring i creating an object it will call default contructor right so the default constructor in this case can only accept Bean.if we are passing string,int . It will throw error. and wont be able to inject the dependency.

? Suppose u are having two constructor one is the default constructor and other one is parametrized Constructor . Then in this Case how the spring will be knowing the difference ? Refer Snippet 13 for reference.


????????????Snippet-13??????????????

Demo demo;
????????public DemoController(Demo demo)
 {
     this.demo=demo;
     logger.info("Creating object {}",this);
 }

???????? public DemoController(int a)
 {
     logger.info("a={}",a); 
 }        

??See in Snippet-13, We have two Constructor , one is Default and the other is Parameterized , So while Spring is creating object , it should be calling constructor , But here Spring is confused that which constructor to call,to distinguish we have to use @Autowired above default constructor . Pls refer Snippet 14.There is a rule in java , parameterized constructor hides the normal constructor in Java.We can call the below parametrized constructor by using new keyword.


????????????Snippet-14??????????????

 Demo demo
????@Autowired
public DemoController(Demo demo)
 {
     this.demo=demo;
     logger.info("Creating object {}",this);
 }

 public DemoController(int a)
 {
     logger.info("a={}",a);
 };        

Earlier , I mentioned that Bean is an object created by Spring ?Is it true ? ?It can be something that spring will create /know during the application startup.It can not be a object only .It can be property also .Suppose we are having in constructor int a . and we want to define int a as a bean . Then we can use application.properties and define it as a custom property

What is predefined property in Application.properties ? Suppose currently server is running on 8080 port which is defined by spring . but somehow , some other process is using that port . In this Case,We can define other port in application. prop- erties file . server.port=8000

We can define two type of properties in application.properties file. a).Custom properties -It means that you are defining thsis property and you are the owner of this property. b).Predefined property in autoconfiguration jar-changing the port of the server is predefined property.

To understand it better, refer to the below attached screenshots - ?Click on ctrl+shift+F. ?Search on server.port in scope. ?U can find the server port is predefined in spring-configuration-metadata.json which in spring-boot-autoconfigure jar .

No alt text provided for this image

See the source type and search the class. ? Do ctrl+N. ?Search the class



org.springframework.boot.autoconfigure.rsocket.RSocketProperties$Server"        
No alt text provided for this image

See in the Above attached screenshot , the class Server is defined .We have defined a property server.port in application.properties and passed it in Constructor .We defined this server.port property in application.properties.

 
????????????Snippet-15??????????????



 public DemoController(@Value("${server.port}") int a)
{
    logger.info("a={}",a);
}        

how can we define our annotation ? Every Annotation is having some kind of target value . Lets check @RestController


????????????Snippet-16??????????????


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

        

You can see that type can be class , interface ,enum or record.


????????????Snippet-17??????????????

public enum ElementType {
    /** Class, interface (including annotation interface), enum, or record
     * declaration */
    TYPE,        

Lets Check @Value-The type can be field , method and anything that mentioned in the snippet.


????????????Snippet-18?????????????

ValueLabsTarget({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
    String value();
}        



????????????Snippet-19??????????????

private int b=8;
@Value("${server.port}")
private int a=2;

public DemoController()
{
    logger.info("a ={}",a);
    logger.info("b ={}",b);
}
private int b=8;
@Value("${server.port}")
private int a=2;

public DemoController()
{
    logger.info("a ={}",a);
    logger.info("b ={}",b);
}        

??Injecting of data will happen but only after the constructor is called .please refer snippet


????????????Snippet-20??????????????

private int b=8;
@Value("${server.port}")
private int a=2;

public DemoController()
{
    logger.info("a ={}",a);
    logger.info("b ={}",b);
}        

Output-

a=2,b=8,Here the server.port in the application.port is 8000. so technically a=8000 but a is 2 because the injection happens after the constructor is defined.

Does the same object can be shared among multiple Class? Lets Check- I - ?Create one Class DemoController and in this class we are using the object of some other Demo class


????????????Snippet-21??????????????

Autowired
Demo demo;

@GetMapping("/sample")
public Demo getDemo()
{
 //   Demo demo=new Demo();
    logger.info("Demo object in sample API {}",demo);
    logger.info("a={}",a);
    return demo;
}        

?Now lets see the output here ? Demo object in sample API - Demo object in sample API com.example.demospring.Demo@678e8ee4

II- ?Create another Class DemoController2 and in this class we are using the object of some other Demo class.


????????????Snippet-22??????????????

@Autowired
Demo demo;

@GetMapping("/sample")
public Demo getDemo()
{
    logger.info("Demo object in sample API {}",demo);
    return demo;

}        

?Now lets see the output here Demo object in sample API in DemoController2 com.example.demospring.Demo@678e8ee4

? We can notice that both the object of Demo Class are same which is shared among different classes. Its acting as a Singleton bean here.

Can the spring create diffrent object for demo class? Yes,the spring can create but for that we have to define the Scope as prototype. so that the class make object depending on the need .

To make u better understand- Lets create a class making the object (Here scope is prototype).It mean that object of this class will be created according to the need .


????????????Snippet-23??????????????

@Component
@Scope("prototype")
public class Demo
{
    public  static Logger logger= LoggerFactory.getLogger(Demo.class);

    public Demo()
    {
        logger.info("Creating instance {}",this);
    }
    private int id=2;
    private String value="abc";

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}        

Firstly , the object of demo will be created of this class, and constructor will be called .Now if another class need the object of demo class , then everytime demo class object will be created."Prototype" means that this bean is not singleton and the object can be created according to the need.

Configuration Annotation-Suppose there is a predefined class for that we need to create object.This can be done with the help of Beans.Lets see how it works. ?Lets create a class DemoConfig.In that class lets use this RestTemplate class


????????????Snippet-24??????????????

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class DemoConfig
{
    public  static Logger logger= LoggerFactory.getLogger(DemoConfig.class);
    @Bean
    public RestTemplate getTemplate()
    {

        RestTemplate restTemplate=new RestTemplate();
        logger.info("Inside restemplate {}",restTemplate);
        return  restTemplate;

    }
@Bean
public RestTemplate getTemplate2()
{
    RestTemplate restTemplate=new RestTemplate();
    logger.info("Inside restemplate {}",restTemplate);
    return  restTemplate;
}

}        

So Basically, This @Bean trying to store the object of this resttemplate in IOC container.Soa for calling this ,we can directly call DemoConfig.getTemplate().So basically when we are calling this method , this method gets executed at the begining of the application and stores the return value as a bean it in the IOC container . so if our function is getting called , it will directly fetch from the IOC container. From the above template , we can see that , we have saved .


????????????Snippet-25??????????????

@Autowire
@Qualifier("getTemplate2")
RestTemplate restTemplate;
        

By mentioning the Qualifier , We can distinguish between two beans .if we are giving the name of the bean . then it will randomly pick the bean .Generally we do not use it.The main use of creating bean is that we dont have to call object everytime we want to call an API .It takes from the IOC container.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了