Java Spring Notes
Java Spring Notes
Jakarta EE
Spring Framework
Spring Framework is an open source Java platform that provides comprehensive infrastructure support
for developing Java applications. Spring Framework is the most popular application framework for
enterprise Java. Spring Framework is an open source framework for the Java platform. It is used to
build Java enterprise applications.
Tight Coupling: When two classes are tightly coupled, they are dependent on each other. If
one class changes, the other class will also change.
Loose Coupling: When two classes are loosely coupled, they are not dependent on each
other. If one class changes, the other class will not change.
In the example below, GameRunner class has a dependency on GamingConsole. Instead of wiring
game object to a specific class such as MarioGame, we can use GamingConsole interface to make it
loosely coupled. So that, we don't need to change our original code. In the future, we can create
classes that implements GamingConsole interface (Polymorphism) and use it.
public class GameRunner {
// public MarioGame game; // Tightly coupled to a specific game, so we need to change this.
private final GamingConsole game; // Loosely coupled, it's not a specific game anymore. Games implement
GamingConsole interface. Polymorphism.
this.game = game;
}
game.up();
game.down();
game.left();
game.right();
Spring Container
Spring Container is the core of the Spring Framework. The Spring Container will create the objects,
wire them together, configure them, and manage their complete life cycle from creation till
destruction. The Spring Container uses DI to manage the components that make up an application.
The Spring Container manages Spring beans and their life cycle.
We have created POJOs (Plain Old Java Objects) and Configuration file. We passed them as inputs into
Spring IoC Container. The Configuration file contains all of the beans. The output of Spring IoC
Container is called Ready System.
JVM (Java Virtual Machine) is the container that runs the Java application. Spring Container is the
container that runs the Spring application. JVM contains Spring Context.
Spring IoC container creates the runtime system for us. Creates Spring Context and manages beans
for us.
BeanFactory Container: Basic IoC container provided by Spring. It is the root interface for
accessing a Spring BeanFactory. It is the simplest container provided by Spring.
ApplicationContext Container: It is the advanced container provided by Spring. It is built
on top of the BeanFactory container. It adds more enterprise-specific functionality like the
ability to resolve textual messages from a properties file and the ability to publish application
events to interested event listeners.
Diagram Example
Difference between Java Bean, POJO and Spring Bean
A POJO is a simple Java object, without any dependency. It does not extend any class and
does not implement any interface. It is a simple Java object that is used to transfer data from
one layer to another.
POJOs do not have any business logic. They are just simple data objects.
POJOs are not thread-safe. They are not synchronized.
POJOs do not have any dependency. They do not have any reference to any other object.
Java Bean
Spring Bean
Spring Bean Configuration is the process of defining beans. The Spring Bean Configuration can be
done in two ways:
We can list all beans managed by Spring Container using the following code:
public class ExampleClass {
System.out.println(beanName);
If multiple matching beans are found, Spring will throw an exception. We can resolve this issue by
using @Qualifier annotation.
Another option is to use @Primary annotation. If we use @Primary annotation, Spring will use the
bean that is marked with @Primary annotation if nothing else is specified.
Primary vs Qualifier
@Primary annotation is used to specify the default bean to be used when multiple beans are
available. @Qualifier annotation is used to specify the bean to be used when multiple beans are
available.
Dependency Injection
Dependency Injection is a design pattern that allows us to remove the hard-coded dependencies and
make our code loosely coupled. It is a process whereby objects define their dependencies, that is, the
other objects they work with, only through constructor arguments, arguments to a factory method, or
properties that are set on the object instance after it is constructed or returned from a factory method.
The container then injects those dependencies when it creates the bean. This process is fundamentally
the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or
location of its dependencies by using direct construction of classes, or a mechanism such as the
Service Locator pattern.
Constructor Injection
Setter Injection
@Autowired
System.out.println("Setter injection");
this.dataService = dataService;
Field Injection
@Autowired
Injection Example
Dependency1 dependency1;
Dependency2 dependency2;
@Autowired
System.out.println("Constructor injection");
this.dependency1 = dependency1;
this.dependency2 = dependency2;
@Override
return "YourBusinessClass{" +
"dependency1=" + dependency1 +
'}';
System.out.println("Setter injection");
this.dependency1 = dependency1;
this.dependency2 = dependency2;
Inversion of Control (IoC) is a design principle in which the control of objects or portions of a program
is transferred to a container or framework. Inversion of Control is a principle in software engineering
by which the control of objects or portions of a program is transferred to a container or framework. The
framework is responsible for managing the life cycle and the flow of control of the application.
In regular programming, the control of objects is in the hands of the programmer. The programmer
creates objects, wires them together, puts them into a configuration, and then the objects are ready to
be used by the application. Inversion of Control reverses this process. The objects are created by a
framework, and the framework wires them together and puts them into a configuration. The
application then uses the objects from the framework.
Dependency Injection (DI) is a software design pattern that implements Inversion of Control for
software applications. The basic idea behind DI is to provide the required dependencies to a class
through external sources rather than creating them inside the class. This external source is called a
container. The container is responsible for creating the dependencies and injecting them into the
class.
Example:
@Service public class BusinessCalculationService {
this.dataService = dataService; }
return Arrays.stream(dataService.retrieveData()).max().orElse(0);
Auto Wiring
Auto Wiring is a process in which Spring automatically wires beans together by inspecting the beans
and matching them with each other.
The default Spring behaviour is Eager initialization. We can change the default behaviour to Lazy
initialization by using @Lazy annotation.
Eager initialization is the recommended approach. Because errors in the configuration are discovered
immediately at application startup. We should use Lazy initialization only when we are sure that the
bean will not be used.
@Component class ClassA {}
@Component @Lazy // ClassB will be created and initialized when it is requested. It will not be created
and initialized at startup. class ClassB {
@Autowired
this.classA = classA;
System.out.println("Doing something");
// We have not requested ClassA bean (not calling it, not loading it); Spring is creating it and
initializing it.
// Even we have not requested ClassB bean (not calling it, not loading it); Spring is creating it and
initializing it. To prevent this, we can use @Lazy annotation. Because by default, Spring creates and
initializes all beans at startup. (Eager initialization)
// Initialization will happen when we request ClassB bean. (When somebody makes use of it)
classB.doSomething();
Bean Scopes
Bean Scopes are used to define the lifecycle of a bean. There are five different bean scopes in Spring:
Singleton
Prototype
Request
Session
Global Session
Singleton Scope
Singleton scope is the default scope of a bean. It means that only one instance of the bean will be
created and shared among all the clients.
It creates only one instance of the bean, and that instance is shared among all the clients.
Prototype Scope
Prototype scope means that a new instance of the bean will be created every time a request is made
for the bean.
It creates a new instance of the bean every time the bean is requested.
To use Prototype scope, we need to use @Scope annotation with @Component annotation.
@Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Employee {
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
// Singleton: The reference in memory is the same. It creates only one instance. (Hash code is the same)
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
// Prototype: The reference in memory is different. It creates a new instance every time. (Hash code is
different)
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
Request Scope
Request scope means that a new instance of the bean will be created for each HTTP request.
Session Scope
Session scope means that a new instance of the bean will be created for each HTTP session.
Global Session scope means that a new instance of the bean will be created for each global HTTP
session.
Java Singleton is a design pattern that restricts the instantiation of a class to one object.
(One object instance per JVM)
Spring Singleton is a bean scope that restricts the instantiation of a bean to one object.
(One object instance per Spring IoC Container)
PostConstruct vs PreDestroy
@Autowired
super();
this.someDependency = someDependency;
// As soon as bean is created, dependencies are injected, and then this method is called by Spring
Framework.
@PostConstruct
someDependency.getReady();
// Do something before bean is removed from the context and application is closed.
@PreDestroy
System.out.println("Cleaning up");
Named: @Named -> @Named("name") is used to specify the name of the bean.
Alternatively, we can use @Component annotation.
Inject: @Inject -> @Inject is used to inject a dependency. Alternatively, we can use
@Autowired annotation.
Qualifier: @Qualifier -> @Qualifier("name") is used to specify the name of the bean.
Alternatively, we can use @Qualifier annotation.
Scope: @Scope -> @Scope("name") is used to specify the scope of the bean. Alternatively,
we can use @Scope annotation.
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<version>2.0.1</version>
</dependency>
return dataService;
// @Autowired
@Inject
System.out.println("Setter injection");
this.dataService = dataService;
Spring XML Configuration is a way of configuring Spring beans using XML files. We can configure beans
using XML files instead of using annotations.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-
context.xsd"> <!-- bean definitions here -->
</bean>
<context:component-scan base-package="com.onurcansever.learnspringframework.game" />
</beans>
To make use of the Spring configuration file, we need to add the following code to the main method.
public class XmlExample {
System.out.println(employee);
context.close();
Why?
this.dataService = dataService;
Spring Core: IoC Container, Dependency Injection, Auto Wiring... (Building web applications,
creating REST API, implementing authentication and authorization, talking to a database,
integrating with other systems, writing great unit tests, etc.)
Spring Projects
Loose Coupling: Spring manages creating and wiring of beans and dependencies. It makes
it maintainable and writing unit tests easily.
Reduced Boilerplate Code: Spring provides a lot of annotations to reduce boilerplate code.
No exception handling.
Architectural Flexibility: Spring Modules and Projects.
Evolution with Time: Microservices and Cloud. (Spring Boot, Spring Cloud etc.)
Extra Notes
// Performs scan for components in the same package (if we don't specify basePackages, it will scan the
package of the class)
@ComponentScan
@ComponentScan(basePackages = "com.onurcansever.learnspringframework.game")
Spring Boot Notes
Quickly
Spring Initializr
Spring Boot Starter Projects: Quickly define dependencies.
Spring Boot Auto Configuration: Automatically provide configuration based on
dependencies in the class.
Spring Boot DevTools: Help us to make changes to the application without restarting the
application.
To add Spring Boot DevTools to the project, add the following dependency to the pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
Production-ready
Logging
Different Configurations for Different Environments (Profiles, ConfigurationProperties)
Monitoring (Spring Boot Actuator)
We can create separate application.properties files and configurations for each environment.
dev:
logging.level.org.springframework=trace
qa
stage
prod:
logging.level.org.springframework=info
For example, to create a profile for development environment, we can create a file named application-
dev.properties in the src/main/resources folder.
logging.level.org.springframework=trace
By default, Spring Boot uses the application.properties file. To use the application-dev.properties file,
we need to specify the profile in the application.properties file.
spring.profiles.active=dev
Values from the default configuration and the profile-specific configuration are merged. If there is a
conflict, the profile-specific configuration wins.
currency-service.username=
currency-service.key=
If we want to create a lot of application configurations, we can create a separate class for
each configuration called ConfigurationProperties.
return url; }
this.url = url; }
return username; }
this.username = username; }
return key; }
this.key = key; }
}
We can also override the default configuration in another profile. For example, in
the application-dev.properties file, we can override the default configuration.
currency-service.url=http://dev.example.com
currency-service.username=devusername
currency-service.key=devkey
File path:
/Users/admin/Desktop/java-spring-boot-udemy/learn-spring-boot/target/
learn-spring-boot-0.0.1-SNAPSHOT.jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
http://localhost:8080/actuator
We can add more features by enabling the following properties in the application.properties file:
management.endpoints.web.exposure.include=*
If we include lots of endpoints, it will consume more CPU and memory. So, we can include only the
endpoints that we need.
management.endpoints.web.exposure.include=beans,health,info
If we want to use JDBC, JPA, Spring Data JPA, Hibernate etc. To do that, we need to create tables in the
H2 database.
We need to create a file called schema.sql in src/main/resources folder. This file will contain the SQL
statements to create the tables.
CREATE TABLE course
);
Spring JDBC
Spring JDBC is a framework that provides a simple, lightweight, and fast way to access the
database.
Write a lot of SQL queries.
Lesser Java code.
""" INSERT INTO course (id, name, author) VALUES (?, ?, ?);
""";
private static String DELETE_QUERY =
springJdbcTemplate.update(DELETE_QUERY, id);
// Single Row
// When we execute SELECT_QUERY, we need to map it because SELECT_QUERY returns multiple rows.
(Kind of like a table) -> RowMapper
// Take the ResultSet and map it to the Course bean. -> RowMapper (They map each row in the
ResultSet to a bean.)
@Repository // Class talks to a database.@Transactional // We want to make use of JPA, so we need to use
@Transactional.public class CourseJpaRepository {
// If we want to make use JPA talk to the database, we need to use EntityManager.
}
public Course findById(long id) {
// This is a Spring Data JPA Repository// We need to create an interface and extend JpaRepository.// We
need to pass the entity class (Course) and the primary key type.public interface
CourseSpringDataJpaRepository extends JpaRepository<Course, Long> {
// Spring Data JPA will create a proxy object for this interface.
// Search by author.
// Follow naming conventions. We are searching by author, so we need to name the method findByAuthor.
Hibernate vs JPA
JPA is a specification. It is an API. (How to define entities, How to map attributes, Who manage
the entities)
Hibernate is an implementation of JPA.
Using Hibernate will lock us to Hibernate. We cannot use other implementations of JPA.
(Toplink, EclipseLink, OpenJPA)
// We want to execute this query at the start of the application. To do that, we need to create a
CommandLineRunner.
// We need to create a Spring Bean of this class. To do that, we need to add @Component annotation.
// @Autowired
@Override
repository.deleteById(1l);
System.out.println(repository.findById(2l));
System.out.println(repository.findById(3l));
repository.findAll().forEach(System.out::println);
System.out.println(repository.count());
System.out.println(repository.findByAuthor("Onur"));