0% found this document useful (0 votes)
212 views117 pages

02 Spring Boot Spring Core

The document discusses Inversion of Control (IoC) and Dependency Injection (DI) in Spring. It explains that Spring's IoC container manages object lifecycles and injections dependencies. The container uses either constructor injection or setter injection to inject dependencies. The document provides an example where the Spring container injects a CricketCoach implementation into a DemoController to demonstrate DI.

Uploaded by

Chotu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
212 views117 pages

02 Spring Boot Spring Core

The document discusses Inversion of Control (IoC) and Dependency Injection (DI) in Spring. It explains that Spring's IoC container manages object lifecycles and injections dependencies. The container uses either constructor injection or setter injection to inject dependencies. The document provides an example where the Spring container injects a CricketCoach implementation into a DemoController to demonstrate DI.

Uploaded by

Chotu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 117

Inversion of Control

© luv2code LLC
Inversion of Control (IoC)

The approach of outsourcing the

construction and management of objects.

www.luv2code.com © luv2code LLC


Coding Scenario
getDailyWorkout()

My App CricketCoach

• App should be configurable

• Easily change the coach for another sport

• Baseball, Hockey, Tennis, Gymnastics etc …

www.luv2code.com © luv2code LLC


Ideal Solution
Object
give me a “Coach” object
Factory
My App

configuration

CricketCoach BaseballCoach
HockeyCoach

www.luv2code.com © luv2code LLC


Spring Container Spring

Object
give me a “Coach” object
Factory
My App

configuration

CricketCoach BaseballCoach
HockeyCoach

www.luv2code.com © luv2code LLC


Spring Container
Spring
• Primary functions Object
Factory
• Create and manage objects (Inversion of Control)

• Inject object dependencies (Dependency Injection)

www.luv2code.com © luv2code LLC


Configuring Spring Container

• XML configuration file (legacy)

• Java Annotations (modern)

• Java Source Code (modern)

www.luv2code.com © luv2code LLC


Spring Dependency Injection

© luv2code LLC
Dependency Injection

The dependency inversion principle.

The client delegates to another object


the responsibility of providing its
dependencies.

www.luv2code.com © luv2code LLC


Car Factory
give me a “Car” object
Car
Factory

www.luv2code.com © luv2code LLC


Spring Container
Spring
Object
give me a “Coach” object
Factory
My App

configuration

dependencies
(helper objects) CricketCoach HockeyCoach BaseballCoach

dependencies dependencies
(helper objects) (helper objects)
www.luv2code.com © luv2code LLC
Spring Container
Spring
• Primary functions Object
Factory
• Create and manage objects (Inversion of Control)

• Inject object’s dependencies (Dependency Injection)

www.luv2code.com © luv2code LLC


Demo Example
• Coach will provide daily workouts

• The DemoController wants to use a Coach

• New helper: Coach DemoController

• This is a dependency
Coach

• Need to inject this dependency

www.luv2code.com © luv2code LLC


Injection Types
• There are multiple types of injection with Spring

• We will cover the two recommended types of injection

• Constructor Injection

• Setter Injection

www.luv2code.com © luv2code LLC


Injection Types - Which one to use?
• Constructor Injection

• Use this when you have required dependencies

• Generally recommended by the spring.io development team as first choice

• Setter Injection

• Use this when you have optional dependencies

• If dependency is not provided, your app can provide reasonable default logic

www.luv2code.com © luv2code LLC


What is Spring AutoWiring DemoController

Coach

• For dependency injection, Spring can use autowiring

• Spring will look for a class that matches

• matches by type: class or interface

• Spring will inject it automatically … hence it is autowired

www.luv2code.com © luv2code LLC


Autowiring Example DemoController

Coach

• Injecting a Coach implementation

• Spring will scan for @Components

• Any one implements the Coach interface???

• If so, let’s inject them. For example: CricketCoach

www.luv2code.com © luv2code LLC


Example Application

/dailyworkout getDailyWorkout()

Web Browser DemoController Coach


“Practice fast bowling “Practice fast bowling
for 15 minutes” for 15 minutes”

www.luv2code.com © luv2code LLC


Development Process - Constructor Injection
1. Define the dependency interface and class
Step-
By-S
tep

2. Create Demo REST Controller

3. Create a constructor in your class for injections

4. Add @GetMapping for /dailyworkout

www.luv2code.com © luv2code LLC


Step 1: Define the dependency interface and class
File: Coach.java

package com.luv2code.springcoredemo;

public interface Coach {


File: CricketCoach.java
String getDailyWorkout();
} package com.luv2code.springcoredemo;

import org.springframework.stereotype.Component;

@Component
public class CricketCoach implements Coach {

@Component annotation @Override


public String getDailyWorkout() {
marks the class return "Practice fast bowling for 15 minutes";
as a Spring Bean }
}

www.luv2code.com © luv2code LLC


@Component annotation
• @Component marks the class as a Spring Bean

• A Spring Bean is just a regular Java class that is managed by Spring

• @Component also makes the bean available for dependency injection

www.luv2code.com © luv2code LLC


Step 2: Create Demo REST Controller
File: DemoController.java

package com.luv2code.springcoredemo;

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

@RestController
public class DemoController {

www.luv2code.com © luv2code LLC


Step 3: Create a constructor in your class for injections
File: DemoController.java

package com.luv2code.springcoredemo; If you only have one constructor then


@Autowired on constructor is optional
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController { @Autowired annotation tells
Spring to inject a dependency
private Coach myCoach;

@Autowired
public DemoController(Coach theCoach) {
myCoach = theCoach;
}

}
At the moment, we only have one Coach implementation CricketCoach.

Spring can figure this out.

Later in the course we will cover


the case of multiple Coach implementations.

www.luv2code.com © luv2code LLC


Step 4: Add @GetMapping for /dailyworkout
File: DemoController.java
package com.luv2code.springcoredemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

private Coach myCoach;

@Autowired
public DemoController(Coach theCoach) {
myCoach = theCoach;
}

@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout();
}
}

www.luv2code.com © luv2code LLC


Constructor Injection

Behind the Scenes

© luv2code LLC
How Spring Processes your application
File: Coach.java File: CricketCoach.java File: DemoController.java
package com.luv2code.springcoredemo; package com.luv2code.springcoredemo; package com.luv2code.springcoredemo;
… …
public interface Coach {
@Component @RestController
String getDailyWorkout(); public class CricketCoach implements Coach { public class DemoController {
}
@Override private Coach myCoach;
public String getDailyWorkout() {
return "Practice fast bowling for 15 minutes"; @Autowired
} public DemoController(Coach theCoach) {
} myCoach = theCoach;
}

}

www.luv2code.com © luv2code LLC


The Spring Framework will perform operations

behind the scenes for you :-)

www.luv2code.com © luv2code LLC


How Spring Processes your application
File: Coach.java File: CricketCoach.java File: DemoController.java
package com.luv2code.springcoredemo; package com.luv2code.springcoredemo; package com.luv2code.springcoredemo;
… …
public interface Coach {
@Component @RestController
String getDailyWorkout(); public class CricketCoach implements Coach { public class DemoController {
}
@Override private Coach myCoach;
public String getDailyWorkout() {
return "Practice fast bowling for 15 minutes"; @Autowired
} public DemoController(Coach theCoach) {
} myCoach = theCoach;
}

}

Spring Framework

Coach theCoach = new CricketCoach(); Constructor


DemoController demoController = new DemoController(theCoach); injection

www.luv2code.com © luv2code LLC


The “new” keyword … is that it???
• You may wonder …

• Is it just the “new” keyword???

• I don’t need Spring for this … I can do this by myself LOL!!!

• Spring is more than just Inversion of Control and Dependency Injection

• For small basic apps, it may be hard to see the benefits of Spring

www.luv2code.com © luv2code LLC


Spring for Enterprise applications
• Spring is targeted for enterprise, real-time / real-world applications

• Spring provides features such as

• Database access and Transactions


Later in the course,
• REST APIs and Web MVC we will build a real-time CRUD REST API
with database access.
• Security
You will see the Spring features in action.
• etc …
Good things are coming :-)

www.luv2code.com © luv2code LLC


Component Scanning

© luv2code LLC
Scanning for Component Classes
• Spring will scan your Java classes for special annotations

• @Component, etc …

• Automatically register the beans in the Spring container

www.luv2code.com © luv2code LLC


Java Source Code

RestController that we created


in an earlier video

Main Spring Boot application class

Created by Spring Initializr

www.luv2code.com © luv2code LLC


Java Source Code
File: SpringcoredemoApplication.java

package com.luv2code.springcoredemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringcoredemoApplication {

public static void main(String[] args) {


SpringApplication.run(SpringcoredemoApplication, args);
}
}

www.luv2code.com © luv2code LLC


Java Source Code
File: SpringcoredemoApplication.java

package com.luv2code.springcoredemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringcoredemoApplication { Enables
public static void main(String[] args) {
Auto configuration
SpringApplication.run(SpringcoredemoApplication, args);
} Component scanning
} Additional configuration

www.luv2code.com © luv2code LLC


Java Source Code
File: SpringcoredemoApplication.java

package com.luv2code.springcoredemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
Composed
public class SpringcoredemoApplication { of following annotations
public static void main(String[] args) {
@EnableAutoConfiguration
SpringApplication.run(SpringcoredemoApplication, args);
} @ComponentScan
} @Configuration

www.luv2code.com © luv2code LLC


Annotations
• @SpringBootApplication is composed of the following annotations:

Annotation Description

@EnableAutoConfiguration Enables Spring Boot's auto-configuration support

Enables component scanning of current package


@ComponentScan
Also recursively scans sub-packages

Able to register extra beans with @Bean


@Configuration
or import other configuration classes

www.luv2code.com © luv2code LLC


Java Source Code
File: SpringcoredemoApplication.java

package com.luv2code.springcoredemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringcoredemoApplication {

public static void main(String[] args) {


SpringApplication.run(SpringcoredemoApplication, args);
}
}

Bootstrap your Spring Boot application

www.luv2code.com © luv2code LLC


Java Source Code
File: SpringcoredemoApplication.java
Behind the scenes …
package com.luv2code.springcoredemo;
Creates application context
import org.springframework.boot.SpringApplication; and registers all beans
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
Starts the embedded server
public class SpringcoredemoApplication { Tomcat etc…
public static void main(String[] args) {
SpringApplication.run(SpringcoredemoApplication, args);
}
}

Bootstrap your Spring Boot application

www.luv2code.com © luv2code LLC


More on Component Scanning
• By default, Spring Boot starts component scanning

• From same package as your main Spring Boot application

• Also scans sub-packages recursively

• This implicitly defines a base search package

• Allows you to leverage default component scanning

• No need to explicitly reference the base package name

www.luv2code.com © luv2code LLC


More on Component Scanning
Scans everything in
com.luv2code.springcoredemo

And any sub-packages (recursively)

Any other sub-packages you create


Can give them any name

Main Spring Boot application class

Automatically component scans package


and sub-packages

www.luv2code.com © luv2code LLC


Common Pitfall - Different location
By default, Spring Boot will not component scan
these packages

Only package of main


Spring Boot application class
1 and sub-packages

Main Spring Boot application class

Automatically component scans package


and sub-packages

www.luv2code.com © luv2code LLC


More on Component Scanning
• Default scanning is fine if everything is under

• com.luv2code.springcoredemo
Explicitly list
base packages to scan
• But what about my other packages?
• com.luv2code.util
org.acme.cart package com.luv2code.springcoredemo;


edu.cmu.srs @SpringBootApplication(

scanBasePackages={"com.luv2code.springcoredemo",
"com.luv2code.util",
"org.acme.cart",
"edu.cmu.srs"})
public class SpringcoredemoApplication {

}

www.luv2code.com © luv2code LLC


Setter Injection

© luv2code LLC
Spring Injection Types

• Constructor Injection

• Setter Injection

www.luv2code.com © luv2code LLC


Inject dependencies by calling

setter method(s) on your class

www.luv2code.com © luv2code LLC


Autowiring Example DemoController

Coach

• Injecting a Coach implementation

• Spring will scan for @Components

• Any one implements the Coach interface???

• If so, let’s inject them. For example: CricketCoach

www.luv2code.com © luv2code LLC


Development Process - Setter Injection

Step-
By-S
tep
1. Create setter method(s) in your class for injections

2. Configure the dependency injection with @Autowired Annotation

www.luv2code.com © luv2code LLC


Step1: Create setter method(s) in your class for injections
File: DemoController.java

@RestController
public class DemoController {

private Coach myCoach;

public void setCoach(Coach theCoach) {


myCoach = theCoach;
}


}

www.luv2code.com © luv2code LLC


Step 2: Configure the dependency injection with Autowired Annotation
File: DemoController.java

@RestController
public class DemoController {

private Coach myCoach;

@Autowired
public void setCoach(Coach theCoach) {
myCoach = theCoach;
}


}

www.luv2code.com © luv2code LLC


The Spring Framework will perform operations

behind the scenes for you :-)

www.luv2code.com © luv2code LLC


How Spring Processes your application
File: Coach.java File: CricketCoach.java File: DemoController.java
public interface Coach { @Component @RestController
public class CricketCoach implements Coach { public class DemoController {
String getDailyWorkout();
} @Override private Coach myCoach;
public String getDailyWorkout() {
return "Practice fast bowling for 15 minutes"; @Autowired
} public void setCoach(Coach theCoach) {
} myCoach = theCoach;
}

}

Spring Framework
Setter injection
Coach theCoach = new CricketCoach();

DemoController demoController = new DemoController();

demoController.setCoach(theCoach);

www.luv2code.com © luv2code LLC


Inject dependencies by calling

ANY method on your class

Simply give: @Autowired

www.luv2code.com © luv2code LLC


Step 2: Configure the dependency injection with Autowired Annotation
File: DemoController.java

@RestController
public class DemoController {

private Coach myCoach; Can use any method name


@Autowired
public void doSomeStuff(Coach theCoach) {
myCoach = theCoach;
}


}

www.luv2code.com © luv2code LLC


Injection Types - Which one to use?
• Constructor Injection

• Use this when you have required dependencies

• Generally recommended by the spring.io development team as first choice

• Setter Injection

• Use this when you have optional dependencies

• If dependency is not provided, your app can provide reasonable default logic

www.luv2code.com © luv2code LLC


Field Injection with
Annotations and Autowiring

© luv2code LLC
Spring Injection Types
• Recommended by the spring.io development team
• Constructor Injection: required dependencies
• Setter Injection: optional dependencies

• Not recommended by the spring.io development team


• Field Injection

www.luv2code.com © luv2code LLC


Field Injection … no longer cool
• In the early days, field injection was popular on Spring projects
• In recent years, it has fallen out of favor

• In general, it makes the code harder to unit test

• As a result, the spring.io team does not recommend field injection


• However, you will still see it being used on legacy projects

www.luv2code.com © luv2code LLC


Inject dependencies by setting field values
on your class directly

(even private fields)

Accomplished by using Java Reflection

www.luv2code.com © luv2code LLC


Step 1: Configure the dependency injection with Autowired Annotation
File: DemoController.java
package com.luv2code.springcoredemo;

import org.springframework.beans.factory.annotation.Autowired;

@RestController
public class DemoController {

@Autowired
private Coach myCoach; Field injection
// no need for constructors or setters

@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout(); Field injection is not recommended by
}
} spring.io development team.

Makes the code harder to unit test.

www.luv2code.com © luv2code LLC


Annotation Autowiring and Qualifiers

© luv2code LLC
Autowiring DemoController

Coach

• Injecting a Coach implementation

• Spring will scan @Components

• Any one implements Coach interface???

• If so, let’s inject them … oops which one?

www.luv2code.com © luv2code LLC


Multiple Coach Implementations

Coach

CricketCoach TennisCoach

BaseballCoach
TrackCoach

www.luv2code.com © luv2code LLC


Multiple Coach Implementations
package com.luv2code.springcoredemo.common; package com.luv2code.springcoredemo.common;

import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;

@Component @Component
public class CricketCoach implements Coach { public class BaseballCoach implements Coach {

@Override @Override
public String getDailyWorkout() { public String getDailyWorkout() {
return "Practice fast bowling for 15 minutes"; return "Spend 30 minutes in batting practice";
} }
} }

package com.luv2code.springcoredemo.common;
package com.luv2code.springcoredemo.common;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Component;
@Component
@Component
public class TrackCoach implements Coach {
public class TennisCoach implements Coach {
@Override
@Override
public String getDailyWorkout() {
public String getDailyWorkout() {
return "Run a hard 5k!";
return "Practice your backhand volley";
}
}
}
}

www.luv2code.com © luv2code LLC


Umm, we have a little problem ….

Parameter 0 of constructor in com.luv2code.springcoredemo.rest.DemoController


required a single bean, but 4 were found:

- baseballCoach
- cricketCoach
- tennisCoach
- trackCoach

www.luv2code.com © luv2code LLC


Solution: Be specific! - @Qualifier
package com.luv2code.springcoredemo.rest;

import com.luv2code.springcoredemo.common.Coach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
… Specify the bean id: cricketCoach
@RestController
public class DemoController { Same name as class, first character lower-case
private Coach myCoach;

@Autowired
public DemoController(@Qualifier("cricketCoach") Coach theCoach) {
myCoach = theCoach;
}

@GetMapping("/dailyworkout")
public String getDailyWorkout() { Other bean ids we could use:
return myCoach.getDailyWorkout();
}
baseballCoach, trackCoach, tennisCoach
}

www.luv2code.com © luv2code LLC


For Setter Injection
• If you are using Setter injection, can also apply @Qualifier annotation

www.luv2code.com © luv2code LLC


Setter Injection - @Qualifier
package com.luv2code.springcoredemo.rest;

import com.luv2code.springcoredemo.common.Coach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
… Give bean id: cricketCoach
@RestController
public class DemoController { Same name as class, first character lower-case
private Coach myCoach;

@Autowired
public void setCoach(@Qualifier("cricketCoach") Coach theCoach) {
myCoach = theCoach;
}

@GetMapping("/dailyworkout")
public String getDailyWorkout() { Other bean ids we could use:
return myCoach.getDailyWorkout();
}
baseballCoach, trackCoach, tennisCoach
}

www.luv2code.com © luv2code LLC


@Primary annotation

© luv2code LLC
Resolving issue with Multiple Coach implementations

• In the case of multiple Coach implementations

• We resolved it using @Qualifier

• We specified a coach by name

• Alternate solution available …

www.luv2code.com © luv2code LLC


Alternate solution

• Instead of specifying a coach by name using @Qualifier

• I simply need a coach … I don’t care which coach

• If there are multiple coaches

• Then you coaches figure it out … and tell me who’s the primary coach

www.luv2code.com © luv2code LLC


Multiple Coach Implementations
package com.luv2code.springcoredemo.common; @Component
public class BaseballCoach implements Coach {

import org.springframework.context.annotation.Primary; }
import org.springframework.stereotype.Component;

@Component
@Primary
public class TrackCoach implements Coach {
@Component
public class TennisCoach implements Coach {
@Override …
public String getDailyWorkout() { }
return "Run a hard 5k!";
}
}

@Component
public class CricketCoach implements Coach {

}

www.luv2code.com © luv2code LLC


Resolved with @Primary
package com.luv2code.springcoredemo.rest;

import com.luv2code.springcoredemo.common.Coach;
import org.springframework.beans.factory.annotation.Autowired; No need for @Qualifier

@RestController There is a @Primary coach


public class DemoController {
This example will use TrackCoach
private Coach myCoach;

@Autowired
public DemoController(Coach theCoach) {
myCoach = theCoach; package com.luv2code.springcoredemo.common;
} import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@GetMapping("/dailyworkout")
@Component
public String getDailyWorkout() { @Primary
return myCoach.getDailyWorkout(); public class TrackCoach implements Coach {
}
@Override
} public String getDailyWorkout() {
return "Run a hard 5k!";
}
}

www.luv2code.com © luv2code LLC


@Primary - Only one

• When using @Primary, can have only one for multiple implementations

• If you mark multiple classes with @Primary … umm, we have a problem

Unsatisfied dependency expressed through constructor parameter 0:


No qualifying bean of type 'com.luv2code.springcoredemo.common.Coach' available:
more than one 'primary' bean found among candidates:
[baseballCoach, cricketCoach, tennisCoach, trackCoach]

www.luv2code.com © luv2code LLC


Mixing @Primary and @Qualifier
• If you mix @Primary and @Qualifier

• @Qualifier has higher priority

www.luv2code.com © luv2code LLC


Mixing @Primary and @Qualifier
package com.luv2code.springcoredemo.rest;

import com.luv2code.springcoredemo.common.Coach;
import org.springframework.beans.factory.annotation.Autowired; @Qualifier has higher priority
import org.springframework.beans.factory.annotation.Qualifier;

Even though there is a @Primary coach
@RestController This example will use CricketCoach
public class DemoController {

private Coach myCoach;

@Autowired
public DemoController(@Qualifier("cricketCoach") Coach theCoach) { package com.luv2code.springcoredemo.common;
myCoach = theCoach; import org.springframework.context.annotation.Primary;
} import org.springframework.stereotype.Component;

@Component
@GetMapping("/dailyworkout") @Primary
public String getDailyWorkout() { public class TrackCoach implements Coach {
return myCoach.getDailyWorkout();
@Override
} public String getDailyWorkout() {
} return "Run a hard 5k!";
}
}

www.luv2code.com © luv2code LLC


Which one: @Primary or @Qualifier?
• @Primary leaves it up to the implementation classes

• Could have the issue of multiple @Primary classes leading to an error

• @Qualifier allows to you be very specific on which bean you want

• In general, I recommend using @Qualifier

• More specific

• Higher priority

www.luv2code.com © luv2code LLC


Lazy Initialization

© luv2code LLC
Initialization

• By default, when your application starts, all beans are initialized

• @Component, etc …

• Spring will create an instance of each and make them available

www.luv2code.com © luv2code LLC


Diagnostics: Add println to constructors
Get the name
of the class
@Component @Component
public class CricketCoach implements Coach { public class BaseballCoach implements Coach {

public CricketCoach() { public BaseballCoach() {


System.out.println("In constructor: " + getClass().getSimpleName()); System.out.println("In constructor: " + getClass().getSimpleName());
} }
… …
} }

@Component @Component
public class TrackCoach implements Coach { public class TennisCoach implements Coach {

public TrackCoach() { public TennisCoach() {


System.out.println("In constructor: " + getClass().getSimpleName()); System.out.println("In constructor: " + getClass().getSimpleName());
} }
… …
} }

www.luv2code.com © luv2code LLC


When we start the application


In constructor: BaseballCoach
In constructor: CricketCoach
In constructor: TennisCoach
In constructor: TrackCoach

By default, when your application starts, all beans are initialized

Spring will create an instance of each and make them available

www.luv2code.com © luv2code LLC


Lazy Initialization
• Instead of creating all beans up front, we can specify lazy initialization

• A bean will only be initialized in the following cases:

• It is needed for dependency injection

• Or it is explicitly requested

• Add the @Lazy annotation to a given class

www.luv2code.com © luv2code LLC


Lazy Initialization with @Lazy
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

Bean is only initialized @Component


@Lazy
if needed for dependency public class TrackCoach implements Coach {
injection
public TrackCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}

}

Inject cricketCoach Since we are NOT injecting TrackCoach …


@RestController
public class DemoController {
it is not initialized

private Coach myCoach;

@Autowired …
public DemoController(@Qualifier("cricketCoach") Coach theCoach) { In constructor: BaseballCoach
myCoach = theCoach;
}
In constructor: CricketCoach
… In constructor: TennisCoach
} …

www.luv2code.com © luv2code LLC


Lazy Initialization

• To configure other beans for lazy initialization

• We would need to add @Lazy to each class

• Turns into tedious work for a large number of classes

• I wish we could set a global configuration property …

www.luv2code.com © luv2code LLC


Lazy Initialization - Global configuration

File: application.properties

spring.main.lazy-initialization=true Once we access REST endpoint /dailywork



Spring will determine dependencies
for DemoController …

All beans are lazy …


no beans are created until needed For dependency resolution
Spring creates instance of CricketCoach first …
Including our DemoController
Then creates instance of DemoController
and injects the CricketCoach

www.luv2code.com © luv2code LLC


Add println to DemoController constructor
@Component
public class CricketCoach implements Coach {
For dependency resolution
public CricketCoach() {
System.out.println("In constructor: " + getClass().getSimpleName()); Spring creates instance of CricketCoach first …
}

}
Then creates instance of DemoController
and injects the CricketCoach
@RestController
public class DemoController {

private Coach myCoach;

@Autowired …
public DemoController(@Qualifier("cricketCoach") Coach theCoach) {
System.out.println("In constructor: " + getClass().getSimpleName()); In constructor: CricketCoach
myCoach = theCoach;
} In constructor: DemoController

} …

www.luv2code.com © luv2code LLC


Lazy Initialization Lazy initialization feature
is disabled by default.

You should profile your application


• Advantages before configuring lazy initialization.

Avoid the common pitfall of premature optimization.


• Only create objects as needed

• May help with faster startup time if you have large number of components

• Disadvantages

• If you have web related components like @RestController, not created until requested

• May not discover configuration issues until too late

• Need to make sure you have enough memory for all beans once created

www.luv2code.com © luv2code LLC


Bean Scopes

© luv2code LLC
Bean Scopes
• Scope refers to the lifecycle of a bean

• How long does the bean live?

• How many instances are created?

• How is the bean shared?

www.luv2code.com © luv2code LLC


Default Scope

Default scope is singleton

www.luv2code.com © luv2code LLC


Refresher: What Is a Singleton?
• Spring Container creates only one instance of the bean, by default

• It is cached in memory

• All dependency injections for the bean

• will reference the SAME bean

www.luv2code.com © luv2code LLC


What is a Singleton?
Spring
@RestController Both point to the same instance
public class DemoController {

private Coach myCoach;


private Coach anotherCoach;

@Autowired
public DemoController( CricketCoach
@Qualifier("cricketCoach") Coach theCoach,
@Qualifier("cricketCoach") Coach theAnotherCoach) {
myCoach = theCoach;
anotherCoach = theAnotherCoach;
}


}

www.luv2code.com © luv2code LLC


Explicitly Specify Bean Scope
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class CricketCoach implements Coach {

www.luv2code.com © luv2code LLC


Additional Spring Bean Scopes

Scope Description

singleton Create a single shared instance of the bean. Default scope.

prototype Creates a new bean instance for each container request.

request Scoped to an HTTP web request. Only used for web apps.

session Scoped to an HTTP web session. Only used for web apps.

Scoped to a global HTTP web session. Only used for web


global-session
apps.

www.luv2code.com © luv2code LLC


Prototype Scope Example
Prototype scope: new object instance for each injection

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CricketCoach implements Coach {

www.luv2code.com © luv2code LLC


Prototype Scope Example
Spring
Prototype scope: new object instance for each injection

@RestController CricketCoach
public class DemoController {

private Coach myCoach;


private Coach anotherCoach;

@Autowired CricketCoach
public DemoController(
@Qualifier("cricketCoach") Coach theCoach,
@Qualifier("cricketCoach") Coach theAnotherCoach) {
myCoach = theCoach;
anotherCoach = theAnotherCoach;
}


}

www.luv2code.com © luv2code LLC


Checking on the scope
@RestController
public class DemoController {

private Coach myCoach;


private Coach anotherCoach;
Check to see if this is the same bean
@Autowired
public DemoController( True or False depending on the bean scope
@Qualifier("cricketCoach") Coach theCoach,
@Qualifier("cricketCoach") Coach theAnotherCoach) {
Singleton: True
myCoach = theCoach;
Prototype: False
anotherCoach = theAnotherCoach;
}

@GetMapping("/check")
public String check() {
return "Comparing beans: myCoach == anotherCoach, " + (myCoach == anotherCoach);
}

}

www.luv2code.com © luv2code LLC


Bean Lifecycle Methods - Annotations

© luv2code LLC
Bean Lifecycle

Container Bean Dependencies Internal Spring Your Custom


Started Instantiated Injected Processing Init Method

Bean Is Ready For Use

Container Is Shutdown

Your Custom
Destroy Method

www.luv2code.com © luv2code LLC


Bean Lifecycle Methods / Hooks
• You can add custom code during bean initialization

• Calling custom business logic methods

• Setting up handles to resources (db, sockets, file etc)

• You can add custom code during bean destruction

• Calling custom business logic method

• Clean up handles to resources (db, sockets, files etc)

www.luv2code.com © luv2code LLC


Init: method configuration
@Component
public class CricketCoach implements Coach {

public CricketCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}

@PostConstruct
public void doMyStartupStuff() {
System.out.println("In doMyStartupStuff(): " + getClass().getSimpleName());
}


}

www.luv2code.com © luv2code LLC


Destroy: method configuration
@Component
public class CricketCoach implements Coach {

public CricketCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}

@PostConstruct
public void doMyStartupStuff() {
System.out.println("In doMyStartupStuff(): " + getClass().getSimpleName());
}

@PreDestroy
public void doMyCleanupStuff() {
System.out.println("In doMyCleanupStuff(): " + getClass().getSimpleName());
}

}

www.luv2code.com © luv2code LLC


Development Process

Step-
By-S
tep
1. Define your methods for init and destroy

2. Add annotations: @PostConstruct and @PreDestroy

www.luv2code.com © luv2code LLC


Configuring Beans with Java Code

© luv2code LLC
Our New Coach …
No sp
anno e cial
tation
s
package com.luv2code.springcoredemo.common;

public class SwimCoach implements Coach {

}
Coach

www.luv2code.com © luv2code LLC


Development Process
Step-
By-S
tep
1. Create @Configuration class

2. Define @Bean method to configure the bean

3. Inject the bean into our controller

www.luv2code.com © luv2code LLC


Step 1: Create a Java class and annotate as @Configuration

package com.luv2code.springcoredemo.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class SportConfig {


}

www.luv2code.com © luv2code LLC


Step 2: Define @Bean method to configure the bean
package com.luv2code.springcoredemo.config;

import com.luv2code.springcoredemo.common.Coach;
import com.luv2code.springcoredemo.common.SwimCoach;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SportConfig {

@Bean The bean id defaults


public Coach swimCoach() { to the method name
return new SwimCoach();
}

www.luv2code.com © luv2code LLC


Step 3: Inject the bean into our controller
package com.luv2code.springcoredemo.rest;

import com.luv2code.springcoredemo.common.Coach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController Inject the bean using


public class DemoController {
the bean id
private Coach myCoach;

@Autowired
public DemoController(@Qualifier("swimCoach") Coach theCoach) {
System.out.println("In constructor: " + getClass().getSimpleName());
myCoach = theCoach;
}


}

www.luv2code.com © luv2code LLC


Use case for @Bean
• You may wonder …

• Using the “new” keyword … is that it???

• Why not just annotate the class with @Component???

www.luv2code.com © luv2code LLC


Use case for @Bean
• Make an existing third-party class available to Spring framework

• You may not have access to the source code of third-party class

• However, you would like to use the third-party class as a Spring bean

www.luv2code.com © luv2code LLC


Real-World Project Example
• Our project used Amazon Web Service (AWS) to store documents

• Amazon Simple Storage Service (Amazon S3)

• Amazon S3 is a cloud-based storage system

• can store PDF documents, images etc

• We wanted to use the AWS S3 client as a Spring bean in our app

www.luv2code.com © luv2code LLC


Real-World Project Example
• The AWS S3 client code is part of AWS SDK

• We can’t modify the AWS SDK source code

• We can’t just add @Component

• However, we can configure it as a Spring bean using @Bean

www.luv2code.com © luv2code LLC


Configure AWS S3 Client using @Bean
package com.luv2code.springcoredemo.config;


import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Configuration
public class DocumentsConfig {

@Bean
public S3Client remoteClient() {

// Create an S3 client to connect to AWS S3


ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
Region region = Region.US_EAST_1;
S3Client s3Client = S3Client.builder()
.region(region)
.credentialsProvider(credentialsProvider)
.build();

return s3Client;
}
}

www.luv2code.com © luv2code LLC


Inject the S3Client as a bean
package com.luv2code.springcoredemo.services;

import software.amazon.awssdk.services.s3.S3Client;

@Component
public class DocumentsService {

private S3Client s3Client;

@Autowired
public DocumentsService(S3Client theS3Client) {
s3Client = theS3Client;
}


}

www.luv2code.com © luv2code LLC


Store our document in S3
package com.luv2code.springcoredemo.services;

import software.amazon.awssdk.services.s3.S3Client;

@Component
public class DocumentsService {

private S3Client s3Client;

@Autowired
public DocumentsService(S3Client theS3Client) {
s3Client = theS3Client;
}

public void processDocument(Document theDocument) {

// get the document input stream and file size …

// Store document in AWS S3


// Create a put request for the object
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(subDirectory + "/" + fileName)
.acl(ObjectCannedACL.BUCKET_OWNER_FULL_CONTROL).build();

// perform the putObject operation to AWS S3 ... using our autowired bean
s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(fileInputStream, contentLength));
}
}

www.luv2code.com © luv2code LLC


Wrap Up
• We could use the Amazon S3 Client in our Spring application

• The Amazon S3 Client class was not originally annotated with @Component

• However, we configured the S3 Client as a Spring Bean using @Bean

• It is now a Spring Bean and we can inject it into other services of our application

• Make an existing third-party class available to Spring framework

www.luv2code.com © luv2code LLC

You might also like