A pretty difficult topic to learn due to a fairly complicated ecosystem surrounding it, with dozens of words that wonât make sense and probably arenât worth figuring out right away. Like many frameworks, oftentimes itâs best to just start coding, even though Spring feels like a major exception at times.
A book that is commonly regarded as being essential to understanding the âtheory.â

Due to my limited understanding of the subject, I couldnât possibly organize the following notes in a logical manner.
Beans
It can be overwhelming at first to see everything called âbeanâ one way or another (seeing LocalContainerEntityManagerFactoryBean as a class is crazy), but itâs surprisingly helpful to know that itâs a continuation of a play on coffee, similar to the Java language itself.
All this to say itâs a managed object in Springâan instance of a class that you defined in Java that is now owned by Spring to be tracked, configured, created, and destroyed. Any class marked with @Component, @Service, @Repository, or @Bean is a bean. You generally donât call new on a bean, this is all Springâs job now.
At this point in the reading, the only annotation you need to worry about is
@Component.
Dependency Injection
A core tenet of the framework. The theory behind it is explained in Java Fundamentals, and it can ultimately be described as a design patternâa way of structuring your code. What most (including myself) fail to realize though with Spring is that dependency injection is something handled by the framework. Youâre not necessarily meant to explicitly write a constructor that accepts a dependency, but rather inform Spring of what your components/services are so that Spring can implicitly create and inject those dependencies without you ever having to specify the new keyword.
There are 3 main types of dependency injection that translate over to Spring:
- Constructor injection
- Setter injection
- Field injection (directly into a public field via
@Autowired)
@Component
public class Adder { }
@Component
public class Multiplier {
@Autowired
Adder adder;
}
// Notice that Multiplier has no constructor that calls `new`, yet Spring will inject an instance of it on startup.How does Spring know when to inject?
A class is marked with the @Component annotation so Spring knows itâs a managed bean. When Spring starts the application, it scans for all components and creates a graph of dependenciesâautomatically creating and injecting them.
In the above code, Spring sees Multiplier needs an Adder â looks for a managed bean of type Adder â injects it.
Configuring/Registering Beans
3 ways:
- XML Based - Where everything is defined in an external XML file. This is a fairly legacy method, but can still be seen.
- Java Configuration - Here we define a separate class tagged with
@Configurationand methods marked as@Bean, which are called by Spring when injecting dependencies. This usually means callingnewyourself in that configuration class. - Annotation Based (Stereotype Annotations) - You register the beans on the classes themselves using annotations like
@Component,@Service,@Repository, or@Autowired(for fields).@Service,@Repository,@Controllerare specializations of@Component.
Good news! Spring Boot automatically scans for components registered via the annotation method. However, if you are using plain Spring (non-boot) or are trying to register components outside the main package, you may need to tell Spring where to look by using the @ComponentScan annotation.
Inversion of Control (IoC)
A buzzword commonly found in the community that refers to a design principle about who is in charge. The term is very similar to dependency injection, but only because dependency injection is one of main ways IoC shows up.
So whatâs an IoC container? Itâs the thing that actually enforces inversion of control. In the context of Spring, the IoC container creates beans, resolves dependencies, injects them, etc.
Thatâs really it.
Bean Scopes
A scope defines a beanâs lifecycle and visibility.
@Scope("singleton")- The default scopeâwhen this bean is requested, the existing object is reused. This scope does not need to be specified.@Scope("prototype")- Any time a bean is requested, a new object is instantiated.
The following are only for use in web applications.
@Scope("request")- A new object is instantiated once per web request.@Scope("session")- A new object is instantiated once per web session.@Scope("application")- A new object is instantiated once per web servlet.@Scope("websocket")- A new object is instantiated once per websocket.
Spring Boot
The aforementioned features are native to Spring itself. Spring Boot primarily aims to achieve the auto-configuration feature, simplifying development with an opinionated approach that has less out of the box configuration. In other words, Spring Boot is Spring with the setup done for you.
You will see the @SpringBootApplication annotation on your main class which automatically includes the @EnableAutoConfiguration annotation. This can be overridden to add support for custom-configuration.
Spring Initializr
A web-based tool provided by Spring that eliminates manually setting up boilerplate. It allows creation of a standard Spring Boot project layout, configures build tools (Maven/Gradle), and adds Spring Boot starters.
In other words, itâs a great tool for initializing a new project.
Spring Boot DevTools
Includes classic features like Live Reload, Automatic Restart, and Remote Debugging.
Spring MVC
Turns HTTP requests into method calls. The front controller (DispatcherServlet) receives all requests, routes them to controller methods, and provides a response. Classes annotated with @Controller or @RESTController define request-handling methodsâreturning an HTML view or data (JSON) view respectively.
The model is usually just a plain old Java object (POJO) that will be passed to a template (or serialized directly to JSON). The view is usually a template engine or frontend of some kind.
A controller will use request mapping, using annotations like @RequestMapping, @GetMapping, @PostMapping, @PutMapping, etc. We can also extract path variables by annotating the method parameter with @PathVariable or request body data with the @RequestBody annotation.
@RequestMappinghas multiple uses. It can be defined at the class level to specify a common base URL for all handler methods within that controller. Or, it can be used at the method level similar to the other annotations:@RequestMapping("/hello", method = RequestMethod.GET).
HTML Response Example
@Controller
public class WebPageController {
@GetMapping("/greeting")
public String greet(Model model) {
// Adding data to the model which will can be accessed by the view
model.addAttribute("message", "Welcome to Spring MVC!");
// Return name of the view (e.g., greeting.html in /templates folder)
return "greeting";
}
}JSON Response Example
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/status")
public Map<String, String> getStatus() {
Map<String, String> response = new HashMap<>();
response.put("status", "running");
response.put("framework", "Spring Boot");
return response;
}
@PostMapping("/submit")
public ResponseEntity<String> submitData(@RequestBody MyDTO data) {
// Simulate processing of the incoming data
String message = String.format("Received data for %s aged %d", data.getName(), data.getAge());
// Return a success response
return ResponseEntity.ok(message);
}
}TODO We can augment the request mapping annotation with the value and params fields like @GetMapping(value = "cats", params = {"amount"}) to only match on URLs that have an âamountâ query parameter.
Parameters (How does a controller get data?)
We can use either @PathVariable for path parameters, @RequestParam for query parameters (?key=value), or @RequestBody for JSON payloads.
All of these are applied to a parameter in the controller method to obtain the data. The method parameter should be the same name as the URL parameter, but this can be overridden if desiredâsearch âoverride the default parameter name in a controller methodâ.
Path Parameters @PathVariable
@GetMapping("/users/{userId}")
public User getUser(@PathVariable long userId) { ... }Query Parameters @RequestParam
// E.g. `/cats?term=fluffy`
@GetMapping("/cats")
public String search(@RequestParam String term) { ... }
Request Body @RequestBody
Note that we need to specify an object (like Cat) where the data from the body will be fit. Spring is somewhat flexible thoughâextra fields will be ignored by default and missing ones will be given null.
// E.g. { "name": "Fluffy", "age": 3 }
@PostMapping("/cats")
public Cat createCat(@RequestBody Cat cat) { ... }Miscellaneous
ResponseEntity class
Used to represent the entire HTTP response, from status code, to headers, to body. Itâs a flexible alternative to a controller method returning a primitive response.
@ExceptionHandler
Used on a controller method to return a response upon encountering the specified exception. E.g. @ExceptionHandler(MissingServletRequestParameterException.class).
@ResponseStatus
Used on a controller method to specify the status code of the response. Often used with on an exception method. E.g. @ResponseStatus(HttpStatus.BAD_REQUEST).
@RESTController
Used on a controller class to specify that the methods return data, not views. It mandates @ResponseBody on every controller method so that return values are written directly to the HTTP response body (JSON). Simply put, itâs used for a RESTful API.
Spring Data
Aims to simplify database access across a variety of data technologies (relational, NoSQL, key-value, and document stores) in Spring-based applications through an abstraction layer. At the core of Spring Data is the repository patternâan interface that defines data access methods. Think of it as yet another Collection interface with methods like findById() and save().
Hierarchy
- JPA - Refers to Java Persistence API, a specification that standardizes Object-Relational Mapping which converts between objects and database tables for database interaction.
- Hibernate - Provides an implementation of JPA with additional features like caching, dirty checking, lazy loading, and more. Hibernate converts Java objects to SQL statements, limiting the need to write SQL.
- Spring Data JPA - A Spring abstraction on top of a JPA implementation (usually Hibernate) which eliminates boilerplate by generating repositories automatically and handling
EntityManagerusage for you.
CrudRepository vs. JpaRepository
These are two interfaces that enable automatic creation of repository implementations that use CRUD operations. JpaRepository extends CrudRepository with additional capabilities like pagination, sorting, locking instances for concurrent access, etc. In other words, JpaRepository is more feature rich at the cost of some complexity.
Step 1. Define your entity
Use a plain old java object (POJO) annotated with @Entity to represent a table. Mark the primary key with @Id (and @GeneratedValue if you want auto-increment). Leverage @OneToOne, @OneToMany, and @ManyToOne for nested objects.
Example
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
private Address address;
}Step 2. Creating a repository
You will define an interface that extends one of the base repository interfaces. Spring Data will automatically detect it and create a concrete class for it without you ever having to worry about the implementation.
The repository requests two types to be specified:
- The entity type (e.g. User) the repository manages
- The type of the entityâs primary key (e.g. Id)
public interface UserRepository extends JpaRepository<User, Long>Step 3. Defining repository methods
There are 3 ways of doing so:
- Inherited CRUD Methods - By extending
JpaRepository, you already have common methods likefindById,deleteById,findAll,save. - Derived Query Methods - This involves parsing the field name out of a method with a common, predefined prefixes like
findBy<field>. You can access nested objects by chaining an underscore likefindBy<field1>_<field2>. The name of the parameter here does not need to match the method name. - Explicit Queries - This involves using
@Queryto define your own SQL statement with parameters preceded by a colon:character.
Example
public interface UserRepository extends JpaRepository<User, Long> {
// --- 1. Inherited CRUD methods (already available) ---
// findById(Long id), save(User user), deleteById(Long id), etc.
// --- 2. Derived Query Methods ---
List<User> findByName(String name); // simple field
List<User> findByAddress_Country(String country); // nested object field
// --- 3. Explicit Queries ---
@Query("SELECT u FROM User u WHERE u.address.country = :country")
List<User> findByCountry(@Param("country") String country);
}Spring Data Transactions
We can use the @Transactional annotation to automatically begin, commit, or roll back a database transaction. Apply it at the method level to wrap a single operation, or at the class level for all methods of the class. We can customize the transaction with attributes like propagation, isolation, and when to trigger rollbacks.
Propagation types:
REQUIRED(Default) - Joins an active transaction if one exists, otherwise start a new one.SUPPORTS- Joins an active transaction if one exists, otherwise run without transaction.MANDATORY- Joins an active transaction if one exists, otherwise throws exception.NEVER- Throws an exception if an active transaction exists.NOT_SUPPORTED- Pauses any active transaction and runs without transactional context.REQUIRES_NEW- Always start a new transaction. If an active one exists, suspend it until this method completes.NESTED- Starts a new transaction if none exists. If one exists, create a savepoint and roll back if exception occurs.
Recomplete Week 10 Day 1 Coding Lab: Spring Transactional
Spring Boot Actuator
A Spring Boot subproject that enables post-production application monitoring and management. Several endpoints are built-in like /health, /info, and /metrics. However, this exposes sensitive information so you will need to be mindful of security.
For example, accessing /health might show a response like "status": "UP".
List of Endpoints
/health- Basic health information./info- Returns arbitrary application information which is empty but customizable by default./metrics- Detailed metrics about the JVM, application usage, and system details./loggers- View and change logging level of application dynamically, good for live debugging./threaddump- Performs a thread dump./heapdump- Performs a heap dump, good for memory related issues./auditevents- Like an event monitoring software, exposes audit-worthy events like authentication attempts, can be customized for your needs./httptrace- Keeps trace information for last 100 HTTP exchanges./env- Provides details about the environment the application is running in.