Java to Spring Boot Journey - Part 1

Image of Java and Springboot logo

# 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

Image of Springboot logo

# @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