Java to Spring Boot Journey - Part 1
# Contents
• Why the Blog?
• Experience and Troubles
• Spring Boot Annotations
• @Autowired Annotation
• @Service and @Component Annotations
• @Transactional Annotation
• @Query Annotation and Query Methods
• Wrap Up
# Why the Blog?
I work with the Spring Boot framework
a lot at my current workplace.
Even though I interact with the framework on a daily basis, I often find myself experiencing imposter syndrome
because I don't truly understand how the framework works.
Surprisingly, I feel that I have a better understanding of other technologies that I work with less frequently
than the one I work with most often.
Therefore, I've set a goal for myself this year: to confront this challenge head-on and document my journey along the way.
# Experience and Troubles
I have some Java
experience
under my belt; it was actually the first programming language I ever learned at
university. I've also written plenty of console applications in Java over the
years.
However, that's probably the first issue
I have; Spring Boot applications are never console
applications but instead usually
event-driven server
applications. In Spring Boot, you won't learn much about an application by drilling down into method
calls within the main method
as you would in traditional Java development.
My second issue
is how heavily the Spring Boot framework relies on annotation-based
code, as an in-line way to inject
code from libraries into your sources files with minimal effort. Coming from my experience with Java, there was only one annotation
I needed to know: @Override
and this annotation was fairly simple to understand. However, in the Spring Boot framework,
there are hundreds
of annotations at our disposal! I must admit, these annotations do lead to cleaner code, but they can also
obscure the underlying meaning of that code.
In the upcoming sections, I'll begin to share some of the key insights and lessons I've learned so far on my Spring Boot learning journey.
# Spring Boot Annotations
# @Autowired Annotation
In both the Java and Spring worlds, memory management
is handled by a system known
as the Garbage Collector
. The primary job of the Garbage Collector is to free up
memory resources that are no longer needed, such as object instances that have become
obsolete.
However, Spring takes this concept a step further by introducing a mechanism to easily share objects within memory
called 'Dependency Injection'
.
This approach helps to avoid creating multiple instances of the same object, thereby reducing memory usage
.
Spring accomplishes this with the @Autowired
annotation. The @Autowired
annotation can be used at both the
field-level
and method-level
.
Below, I will compare the Java way versus the Spring way.
Java:
public class A {
private Service service = new Service(); // 1st instance
}
public class B {
private Service service = new Service(); // 2nd instance
}
Spring:
public class A {
@Autowired
private Service service; // All share 1 instance
}
public class B {
@Autowired
private Service service; // All share 1 instance
}
The above illustrates the memory efficiency that Spring can achieve through the use of the @Autowired
annotation.
# @Service and @Component Annotations
As far as I understand, Spring's memory management capabilities are exclusive to
object instances it identifies as Spring Beans
. This magic doesn't extend to standard
Java POJOs
(Plain Old Java Objects).
public class A {
private Service service = new Service(); // POJO
}
public class B {
@Autowired
private Service service; // Spring Bean
}
So, how are Spring Beans
defined? In Spring Boot, many of the annotations you encounter are actually creating
Spring Beans behind the scenes. These beans can be created at the class-level
, method-level
and field-level
.
I'm going to discuss two
commonly used class-level Spring Bean annotations in Spring Boot: @Service
and @Component
.
Both the @Service
and @Component
annotations can be used interchangeably as they function similarly.
However, we typically use @Service
for semantic reasons to enhance the readability and more accurately
describe the class's functionality. A good rule of thumb is to consider whether the class is handling the
orchestration of business logic
. If so, then it is a Service, and the @Service
annotation should be used.
On the other hand, the @Component
annotation is more suitable for simple
or generic
classes that do not
encapsulate any business logic.
Below is a brief examples of the @Service
and @Component
annotations to illustrate how each is
typically used in Spring Boot applications.
@Service
public class BookService {
// Has methods to:
// orchestrate database CRUD operations
// orchestrate external API calls
}
@Component
public class SimpleLogger {
// Has simple methods to output to console
}
# @Transactional Annotation
In the programming world, when we make changes to a database, we prefer those changes
to either fully succeed
or fully fail
, rather than partially succeed
. This
concept is known in the database world as an 'Atomic Transaction'
.
In Spring Boot, there is an annotation designed to handle similar scenarios, called @Transactional
.
This annotation ensures that a series of operations within a transaction boundary either all succeed or all fail together.
Below is a brief example demonstrating the use of the @Transactional
annotation.
@Transactional
public void transferFunds(String, senderId, String receiverId, Long amount) {
// Executes an SQL statement that needs to:
// 1. Deduct the amount from SENDERS account
// 2. Add the same amount RECEIVERS account
// Both these steps must occur or all hell breaks loose.
}
# @Query Annotation and Query Methods
Another discovery from my journey so far with Spring Boot is the variety of options
it offers for executing SQL
commands with relational databases
.
One feature I've come across is the @Query
annotation, which basically allows you to define and execute raw,
explicit SQL statements directly.
However, another intriguing feature I've discovered is a feature that comes part of the Spring Data JPA
library,
called Query Methods
. This isn't just another annotation like @Query
. Instead, it presents an alternative approach
.
With Query Methods
, you can use a special syntax to embed SQL statements
directly in the method signature
itself,
offering a distinct and streamlined way to execute queries!
To help illustrate both of these approaches, below is a brief example of the @Query
annotation and Query Methods
.
// Exact same SQL statement via. @Query annotation
@Query(value = "SELECT * FROM BOOK WHERE PUBLISHER = ?1", nativeQuery = true)
List<Book> getBooksQuery(String publisher);
// Exact same SQL statement via. Query Methods
List<Book> findAllBooksByPublisher(Publisher publisher);
# Wrap Up
This sums up the most valuable insights I've learned so far and deemed worth sharing. I plan to continue this blog series as I delve deeper into the Spring Boot framework.
Thank you for reading.
Ben Diep
Software Engineer