Table of contents
- Chapter 1: Introduction to Spring Framework
- Chapter 2: Configuring Spring Applications
- Chapter 3: Dependency Injection in Detail
- Chapter 4: Bean Scopes and Lifecycle
- Chapter 5: Aspects and Cross-Cutting Concerns (AOP)
- Chapter 6: Spring MVC and Web Applications
- Chapter 7: Working with REST Clients
- Chapter 8: Database Access with Spring
- Chapter 9: Spring Data (JPA)
- Chapter 10: Spring Boot
- Chapter 11: Spring Boot Advanced Topics (outline)
- Chapter 12: Security and Best Practices (outline)
Spring Start Here - Complete Study Notes (Textbook Style)
Based on Spring Start Here by Laurentiu Spilca (compiled and expanded).
Chapter plan
- Chapter 1: Introduction to Spring Framework
- Chapter 2: Configuring Spring Applications
- Chapter 3: Dependency Injection in Detail
- Chapter 4: Bean Scopes and Lifecycle
- Chapter 5: Aspects and Cross-Cutting Concerns (AOP)
- Chapter 6: Spring MVC and Web Applications
- Chapter 7: Working with REST Clients
- Chapter 8: Database Access with Spring
- Chapter 9: Spring Data
- Chapter 10: Testing in Spring
- Chapter 11: Spring Boot and Autoconfiguration
- Chapter 12: Security and Best Practices
Chapter 1 - Introduction to the Spring Framework
1.1 Why Spring Exists
Early Java applications were a mess of manually created objects. Every class constructed its own dependencies and hard-wired them together, which meant:
- Zero flexibility: you had to rewrite code to swap an implementation.
- No testability: you could not isolate components without rewriting constructors.
- Brittle architecture: changing one class broke five others.
Spring was designed to fix this by introducing Inversion of Control (IoC): the framework, not your code, controls object creation and wiring.
1.2 Inversion of Control (IoC)
Traditional control flow:
public class InvoiceService {
private final EmailService emailService = new EmailService();
public void sendInvoice() {
emailService.send("invoice.pdf");
}
}Here, InvoiceService creates its own EmailService. You cannot replace it with a mock or a different implementation.
IoC flow:
public class InvoiceService {
private final EmailService emailService;
public InvoiceService(EmailService emailService) {
this.emailService = emailService;
}
public void sendInvoice() {
emailService.send("invoice.pdf");
}
}Now, someone else decides which EmailService to use. That "someone else" is Spring's IoC container.
1.3 The Spring IoC Container
The container is the brain of a Spring application. It:
- Instantiates objects (called beans)
- Resolves dependencies among them
- Manages their lifecycle (creation, initialization, destruction)
Think of it as a registry:
Bean name -> Bean instanceWhenever your code asks for a dependency, the container supplies it.
1.4 Dependency Injection (DI)
IoC is the principle; Dependency Injection is the concrete mechanism Spring uses to implement it.
- Constructor injection: preferred for mandatory dependencies
- Setter injection: optional dependencies
- Field injection: avoid in serious projects
Example:
@Component
public class EmailService {
public void send(String message) {
System.out.println("Sending: " + message);
}
}
@Component
public class InvoiceService {
private final EmailService emailService;
@Autowired
public InvoiceService(EmailService emailService) {
this.emailService = emailService;
}
public void sendInvoice() {
emailService.send("Invoice sent");
}
}When the application starts, Spring detects both components, creates them, and injects EmailService into InvoiceService automatically.
1.5 How Spring Knows What to Manage
Spring needs configuration telling it which classes to treat as beans.
1.5.1 Annotation-based configuration
@Configuration
@ComponentScan("com.company.billing")
public class AppConfig {
}@Configurationmarks a class that defines bean setup.@ComponentScantells Spring where to look for@Component,@Service,@Repository, and@Controllerclasses.
1.5.2 Java-based bean definition
@Configuration
public class BeanConfig {
@Bean
public EmailService emailService() {
return new EmailService();
}
@Bean
public InvoiceService invoiceService(EmailService emailService) {
return new InvoiceService(emailService);
}
}Each @Bean method returns an object to be managed by the IoC container.
1.6 Creating and Using the Context
public class Main {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(BeanConfig.class)) {
InvoiceService invoiceService = context.getBean(InvoiceService.class);
invoiceService.sendInvoice();
}
}
}AnnotationConfigApplicationContext loads the configuration, builds the beans, resolves dependencies, and runs the application.
1.7 Advantages of IoC and DI
| Problem Without IoC | Solved By Spring | | --- | --- | | Tight coupling between classes | Dependencies are injected via interfaces | | Hard to test | You can inject mocks or stubs | | Complex object creation | Centralized in configuration | | Lifecycle management | Spring handles it automatically |
1.8 Common Pitfalls
- Circular dependencies: Spring throws
BeanCurrentlyInCreationException. Fix by redesigning or introducing an interface boundary. - Using field injection: makes testing painful. Prefer constructor injection.
- Overusing configuration: do not add every object to the context; only those that need Spring features.
1.9 Mini Project - IoC and DI in Action
Goal: create a small greeting application using Spring's IoC container.
Step 1: define components
@Component
public class MessageService {
public String getMessage() {
return "Hello from Spring!";
}
}Step 2: inject dependency
@Component
public class GreetingApp {
private final MessageService messageService;
@Autowired
public GreetingApp(MessageService messageService) {
this.messageService = messageService;
}
public void greet() {
System.out.println(messageService.getMessage());
}
}Step 3: run the context
@Configuration
@ComponentScan("com.example")
public class AppConfig { }
public class Main {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class)) {
GreetingApp app = context.getBean(GreetingApp.class);
app.greet();
}
}
}Output:
Hello from Spring!1.10 Summary
- IoC: framework controls object creation instead of user code.
- DI: mechanism by which Spring provides dependencies.
- Bean: any object managed by Spring.
- ApplicationContext: core container managing all beans.
@Configuration+@Beanor@Component+@ComponentScan: two main ways to define beans.- Use constructor injection to ensure immutability and testability.
Chapter 2 - Configuring Spring Applications
2.1 What Configuration Really Means
Configuration in Spring is the process of telling the framework which objects to manage, how they relate, and what rules apply to their lifecycle.
Spring needs two types of information:
- Where to look for components
- What additional beans or settings to create manually
You can provide this via:
- Java configuration (
@Configuration,@Bean) - Annotation scanning (
@ComponentScan) - Optional extras: XML, YAML, or programmatic registration
2.2 The Application Context
When you start a Spring app, the framework creates an ApplicationContext, which acts as a registry of beans.
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
MyService service = context.getBean(MyService.class);2.3 Defining Configuration Classes
@Configuration
public class AppConfig {
// beans go here
}@Configuration marks this class as a source of bean definitions.
2.4 Defining Beans with @Bean
@Configuration
public class BeanConfig {
@Bean
public Parrot parrot() {
Parrot p = new Parrot();
p.setName("Miki");
return p;
}
}2.5 Bean Naming and Aliases
Default name is the method name, but you can specify custom names and aliases:
@Bean("bird")
public Parrot parrot() {
return new Parrot("Miki");
}
@Bean({"bird", "featheredFriend"})
public Parrot parrot2() {
return new Parrot("Kiki");
}2.6 Linking Beans Inside Configuration
Option 1: method call wiring
@Bean
public Person person() {
Person p = new Person();
p.setParrot(parrot());
return p;
}Option 2: parameter injection (preferred)
@Bean
public Person person(Parrot parrot) {
return new Person("John", parrot);
}2.7 Stereotype Annotations
| Annotation | Purpose |
| --- | --- |
| @Component | Generic Spring-managed component |
| @Service | Marks a service layer class |
| @Repository | Marks a data access object (DAO) |
| @Controller | Marks a web controller |
| @RestController | Marks a REST API controller |
Example:
@Component
public class Parrot {
private String name = "Miki";
}2.8 Component Scanning
@Configuration
@ComponentScan("com.example.zoo")
public class AppConfig { }2.9 @Primary and @Qualifier
@Bean
@Primary
public Parrot parrot1() { return new Parrot("Miki"); }
@Bean
public Parrot parrot2() { return new Parrot("Kiki"); }
@Bean
public Person person(@Qualifier("parrot2") Parrot parrot) {
return new Person("John", parrot);
}2.10 Lifecycle Hooks
@Component
public class Parrot {
@PostConstruct
void init() {
System.out.println("Parrot ready for action!");
}
@PreDestroy
void cleanup() {
System.out.println("Parrot signing off...");
}
}2.11 Programmatic Bean Registration
context.registerBean("customBean", MyClass.class, MyClass::new);2.12 Example - Wiring Components Together
Parrot:
@Component
public class Parrot {
private String name = "Miki";
public String getName() { return name; }
}Person:
@Component
public class Person {
private final Parrot parrot;
@Autowired
public Person(Parrot parrot) {
this.parrot = parrot;
}
public void introduce() {
System.out.println("My parrot is " + parrot.getName());
}
}AppConfig:
@Configuration
@ComponentScan("com.example")
public class AppConfig { }Main:
public class Main {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class)) {
Person person = context.getBean(Person.class);
person.introduce();
}
}
}Output:
My parrot is Miki2.13 Key Takeaways
| Concept | Description |
| --- | --- |
| @Configuration | Marks class as a Spring config source |
| @Bean | Creates a bean manually |
| @Component, @Service, etc. | Automatically detected beans |
| @ComponentScan | Tells Spring where to look for annotated classes |
| @Primary | Marks one bean as default when multiple exist |
| @Qualifier | Chooses a specific bean by name |
| @PostConstruct / @PreDestroy | Hooks for init and destroy logic |
Chapter 3 - Dependency Injection in Detail
3.1 Why Dependency Injection Exists
DI enforces inversion of control by removing the new keyword from your codebase. You declare dependencies; Spring provides them.
Without DI:
public class OrderService {
private final EmailService emailService = new EmailService();
}With DI:
public class OrderService {
private final EmailService emailService;
@Autowired
public OrderService(EmailService emailService) {
this.emailService = emailService;
}
}3.2 Types of Dependency Injection
Constructor injection (preferred):
@Component
public class UserService {
private final NotificationService notificationService;
@Autowired
public UserService(NotificationService notificationService) {
this.notificationService = notificationService;
}
}Setter injection (optional dependencies):
@Component
public class UserService {
private NotificationService notificationService;
@Autowired
public void setNotificationService(NotificationService notificationService) {
this.notificationService = notificationService;
}
}Field injection (avoid):
@Component
public class UserService {
@Autowired
private NotificationService notificationService;
}3.3 How Spring Resolves Dependencies
Spring builds a dependency graph, matches dependencies by type, then by name (if qualifiers are used). Multiple candidates require @Qualifier or @Primary.
3.4 Example - Automatic Wiring
NotificationService:
@Component
public class NotificationService {
public void notifyUser(String msg) {
System.out.println("Sending notification: " + msg);
}
}UserService:
@Component
public class UserService {
private final NotificationService notificationService;
@Autowired
public UserService(NotificationService notificationService) {
this.notificationService = notificationService;
}
public void register(String user) {
System.out.println(user + " registered!");
notificationService.notifyUser("Welcome " + user);
}
}3.5 Interface-Based Injection
public interface PaymentProcessor {
void process(double amount);
}
@Component
public class CreditCardProcessor implements PaymentProcessor {
public void process(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}@Component
public class PaymentService {
private final PaymentProcessor processor;
@Autowired
public PaymentService(PaymentProcessor processor) {
this.processor = processor;
}
public void pay(double amount) {
processor.process(amount);
}
}3.6 Multiple Beans of the Same Type
@Component("creditCardProcessor")
public class CreditCardProcessor implements PaymentProcessor { }
@Component("paypalProcessor")
public class PayPalProcessor implements PaymentProcessor { }@Autowired
@Qualifier("paypalProcessor")
private PaymentProcessor processor;3.7 Optional Dependencies
@Autowired(required = false)
private AuditService auditService;Or:
@Autowired
private Optional<AuditService> auditService;3.8 Circular Dependencies
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}Fix by redesigning, or as a last resort use @Lazy:
@Component
public class B {
@Autowired
@Lazy
private A a;
}3.9 Profiles
@Component
@Profile("dev")
public class LocalDatabase implements Database { }
@Component
@Profile("prod")
public class CloudDatabase implements Database { }3.10 Practical Example - Multiple Payment Strategies
public interface PaymentProcessor {
void process(double amount);
}
@Component("credit")
public class CreditCardProcessor implements PaymentProcessor {
public void process(double amount) {
System.out.println("Paid $" + amount + " via Credit Card");
}
}
@Component("upi")
public class UPIProcessor implements PaymentProcessor {
public void process(double amount) {
System.out.println("Paid $" + amount + " via UPI");
}
}
@Component
public class PaymentService {
private final PaymentProcessor processor;
@Autowired
public PaymentService(@Qualifier("upi") PaymentProcessor processor) {
this.processor = processor;
}
public void makePayment(double amount) {
processor.process(amount);
}
}3.11 Testing with Mocked Dependencies
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig.class)
public class PaymentServiceTest {
@MockBean
private PaymentProcessor mockProcessor;
@Autowired
private PaymentService paymentService;
@Test
void testMakePayment() {
paymentService.makePayment(100.0);
verify(mockProcessor).process(100.0);
}
}3.12 Summary
| Type | Description | Recommended Use |
| --- | --- | --- |
| Constructor Injection | Dependencies passed via constructor | Preferred |
| Setter Injection | Dependencies passed via setter | Optional dependencies |
| Field Injection | Direct field assignment | Avoid |
| @Qualifier | Select between multiple beans | Multiple candidates |
| @Primary | Marks default bean | One bean should be default |
| @Lazy | Delays bean creation | Break circular dependencies |
| @Profile | Conditional bean creation | Environment-based configs |
Chapter 4 - Bean Scopes and Lifecycle
4.1 What a Bean Scope Means
Scope defines how many instances of a bean Spring creates and how long they live.
4.2 The Main Scopes
| Scope | Description | Typical Use | | --- | --- | --- | | singleton | One instance per container | Stateless services | | prototype | New instance per request | Short-lived stateful objects | | request | One per HTTP request | Request data | | session | One per HTTP session | User session state | | application | One per ServletContext | Shared app state | | websocket | One per WebSocket session | Realtime sessions |
4.3 Singleton Scope (Default)
@Component
public class SingletonBean {
public SingletonBean() {
System.out.println("Singleton created!");
}
}4.4 Prototype Scope
@Component
@Scope("prototype")
public class PrototypeBean {
public PrototypeBean() {
System.out.println("Prototype created!");
}
}Spring does not manage prototype beans after creation; you handle cleanup.
4.5 Lazy vs Eager Initialization
@Component
@Lazy
public class ExpensiveService {
public ExpensiveService() {
System.out.println("Initialized only when needed");
}
}4.6 Lifecycle Overview
- Instantiation
- Dependency injection
- Initialization
- Usage
- Destruction
4.7 @PostConstruct and @PreDestroy
@Component
public class DatabaseConnection {
@PostConstruct
void connect() {
System.out.println("Connecting to database...");
}
@PreDestroy
void disconnect() {
System.out.println("Closing database connection...");
}
}4.8 InitializingBean and DisposableBean
@Component
public class FileManager implements InitializingBean, DisposableBean {
public void afterPropertiesSet() {
System.out.println("FileManager initialized");
}
public void destroy() {
System.out.println("FileManager destroyed");
}
}4.9 Custom Init and Destroy Methods
@Bean(initMethod = "init", destroyMethod = "cleanup")
public Cache cache() {
return new Cache();
}4.10 Web Scopes and Scoped Proxies
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestTracker {
private final String id = UUID.randomUUID().toString();
public String getId() { return id; }
}4.11 Prototype Inside Singleton
Prototype beans injected into singletons are resolved once at singleton creation time. Use ObjectProvider to get a fresh instance:
@Component
@Scope("singleton")
public class SingletonService {
@Autowired
private ObjectProvider<PrototypeService> provider;
public void run() {
System.out.println(provider.getObject().hashCode());
}
}4.12 Common Pitfalls
- Mixing scopes blindly (prototype into singleton without provider/proxy).
- Holding mutable state in singletons (race conditions).
- Forgetting to close contexts (
@PreDestroynever runs). - Ignoring lifecycle hooks (leaking resources).
Chapter 5 - Aspects and Cross-Cutting Concerns (AOP)
5.1 The Problem AOP Solves
Cross-cutting concerns include logging, security, transactions, metrics, and exception handling.
Without AOP:
public void createOrder(Order order) {
System.out.println("Start transaction");
// business logic
System.out.println("Commit transaction");
}5.2 What AOP Does
Spring AOP applies extra behavior via proxies. Method calls go through a generated proxy that runs advice before/after/around the target method.
5.3 AOP Terminology
| Term | Meaning | | --- | --- | | Aspect | Class containing cross-cutting behavior | | Advice | Code to run at a join point | | Join Point | Point in execution (e.g., method call) | | Pointcut | Rule defining which join points to target | | Weaving | Applying aspects (Spring does runtime proxy weaving) |
5.4 Enabling AOP
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example")
public class AppConfig { }5.5 Example - Logging Aspect
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Method execution started");
}
@After("execution(* com.example.service.*.*(..))")
public void logAfter() {
System.out.println("Method execution finished");
}
}5.6 @Around Advice
@Aspect
@Component
public class PerformanceAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object measureExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long end = System.currentTimeMillis();
System.out.println(pjp.getSignature() + " took " + (end - start) + " ms");
return result;
}
}5.7 Advice Types
| Annotation | Timing | Example |
| --- | --- | --- |
| @Before | Before method executes | logging, security checks |
| @After | After method executes (always) | cleanup |
| @AfterReturning | After method returns | auditing |
| @AfterThrowing | After method throws | error logging |
| @Around | Wraps the entire call | profiling, transactions |
5.8 Custom Annotation Pointcuts
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ToLog { }@Aspect
@Component
public class AnnotationLogger {
@Before("@annotation(com.example.ToLog)")
public void logMethod() {
System.out.println("Custom log before method annotated with @ToLog");
}
}5.9 Ordering
@Aspect
@Order(1)
@Component
public class SecurityAspect { }
@Aspect
@Order(2)
@Component
public class LoggingAspect2 { }5.10 Limitations
- Spring AOP works only on Spring-managed beans.
- Typically intercepts public methods.
- Does not intercept static/private/final methods.
- Proxy-based (runtime) weaving.
Chapter 6 - Spring MVC and Web Applications
6.1 Big Picture
Spring MVC separates Model (data), View (UI/representation), and Controller (request handling).
DispatcherServlet is the front controller: every request goes through it.
6.2 Request Flow
Browser -> DispatcherServlet -> HandlerMapping -> Controller -> ViewResolver -> Response6.3 Basic Controller
@Controller
public class HelloController {
@RequestMapping("/hello")
public String sayHello(Model model) {
model.addAttribute("message", "Hello from Spring MVC!");
return "greeting";
}
}6.4 @RestController
@RestController
@RequestMapping("/api")
public class GreetingController {
@GetMapping("/greet")
public Map<String, String> greet() {
return Map.of("message", "Hello, REST world!");
}
}6.5 Mapping Annotations
| Annotation | HTTP Method |
| --- | --- |
| @GetMapping | GET |
| @PostMapping | POST |
| @PutMapping | PUT |
| @DeleteMapping | DELETE |
| @PatchMapping | PATCH |
6.6 Path Variables and Query Params
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable int id) {
return "User ID: " + id;
}
@GetMapping
public String search(@RequestParam String name) {
return "Searching for: " + name;
}
}6.7 JSON Input/Output
@RestController
@RequestMapping("/employees")
public class EmployeeController {
@PostMapping
public String addEmployee(@RequestBody Employee emp) {
return "Added " + emp.getName();
}
}6.8 ResponseEntity
@GetMapping("/{id}")
public ResponseEntity<Employee> getEmployee(@PathVariable int id) {
Employee emp = service.find(id);
if (emp == null)
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
return ResponseEntity.ok(emp);
}6.9 Exception Handling
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleInvalidArg(IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleAll(Exception ex) {
return ResponseEntity.status(500).body("Server error: " + ex.getMessage());
}
}6.10 Validation with @Valid
@PostMapping("/register")
public ResponseEntity<String> register(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors())
return ResponseEntity.badRequest().body("Invalid data");
return ResponseEntity.ok("User registered");
}Chapter 7 - Working with REST Clients
7.1 Options
RestTemplate(blocking)WebClient(reactive)- OpenFeign (declarative)
7.2 RestTemplate Bean
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}7.3 GET
String response = restTemplate.getForObject(url, String.class);7.4 POST
Employee created = restTemplate.postForObject(url, emp, Employee.class);7.5 Headers and Exchange
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer xyz123");
HttpEntity<Employee> entity = new HttpEntity<>(emp, headers);
ResponseEntity<Employee> response =
restTemplate.exchange(url, HttpMethod.POST, entity, Employee.class);7.6 WebClient Setup
@Bean
public WebClient webClient() {
return WebClient.builder().baseUrl("https://api.example.com").build();
}7.7 WebClient GET
public Mono<String> getWeather() {
return webClient.get()
.uri("/weather?q=London")
.retrieve()
.bodyToMono(String.class);
}7.8 OpenFeign
@FeignClient(name = "weatherClient", url = "https://api.weatherapi.com/v1")
public interface WeatherClient {
@GetMapping("/current.json")
WeatherResponse getWeather(@RequestParam("q") String city,
@RequestParam("key") String apiKey);
}Chapter 8 - Database Access with Spring
8.1 DataSource and JdbcTemplate
@Configuration
public class JdbcConfig {
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}8.2 CRUD
jdbcTemplate.execute("CREATE TABLE employees (id INT PRIMARY KEY, name VARCHAR(50), dept VARCHAR(50))");
jdbcTemplate.update("INSERT INTO employees (id, name, dept) VALUES (?, ?, ?)", 1, "Nishanth", "Engineering");
jdbcTemplate.update("UPDATE employees SET dept=? WHERE id=?", "IT", 1);
jdbcTemplate.update("DELETE FROM employees WHERE id=?", 1);8.3 RowMapper
List<Employee> list = jdbcTemplate.query("SELECT * FROM employees", (rs, n) ->
new Employee(rs.getInt("id"), rs.getString("name"), rs.getString("dept"))
);8.4 Transactions
@Service
public class TransferService {
private final JdbcTemplate jdbcTemplate;
@Autowired
public TransferService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Transactional
public void transfer(int from, int to, double amount) {
jdbcTemplate.update("UPDATE account SET balance=balance-? WHERE id=?", amount, from);
jdbcTemplate.update("UPDATE account SET balance=balance+? WHERE id=?", amount, to);
}
}8.5 NamedParameterJdbcTemplate
String sql = "INSERT INTO employees (id, name, dept) VALUES (:id, :name, :dept)";
Map<String, Object> params = Map.of("id", 2, "name", "Ravi", "dept", "HR");
namedJdbc.update(sql, params);Chapter 9 - Spring Data (JPA)
9.1 Repository Interfaces
| Interface | Purpose |
| --- | --- |
| CrudRepository | Basic CRUD |
| PagingAndSortingRepository | Pagination and sorting |
| JpaRepository | JPA-specific enhancements |
Example:
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer> { }9.2 Derived Query Methods
List<Employee> findByDept(String dept);
Employee findByName(String name);
List<Employee> findByDeptAndName(String dept, String name);
List<Employee> findTop3ByDept(String dept);
boolean existsByName(String name);
long countByDept(String dept);9.3 @Query and @Modifying
@Query("SELECT e FROM Employee e WHERE e.name LIKE %:name%")
List<Employee> searchByName(@Param("name") String name);@Modifying
@Transactional
@Query("UPDATE Employee e SET e.dept = :dept WHERE e.id = :id")
void updateDept(@Param("id") int id, @Param("dept") String dept);9.4 Pagination
Page<Employee> findByDept(String dept, Pageable pageable);9.5 Auditing
@Configuration
@EnableJpaAuditing
public class JpaConfig { }Chapter 10 - Spring Boot
10.1 Boot Entry Point
@SpringBootApplication
public class EmployeeApp {
public static void main(String[] args) {
SpringApplication.run(EmployeeApp.class, args);
}
}@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan.
10.2 Starters
Common starters:
spring-boot-starter-webspring-boot-starter-data-jpaspring-boot-starter-testspring-boot-starter-securityspring-boot-starter-thymeleafspring-boot-starter-actuator
10.3 application.properties / application.yml
server.port=8081
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true10.4 Profiles
spring.profiles.active=prod10.5 Actuator
Common endpoints:
/actuator/health/actuator/info/actuator/metrics
10.6 CommandLineRunner
@Component
public class StartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("App started successfully!");
}
}10.7 Building the Executable Jar
mvn clean package
java -jar target/employee-app-0.0.1-SNAPSHOT.jarChapter 11 - Spring Boot Advanced Topics (Outline)
Not expanded in these notes yet.
Chapter 12 - Security and Best Practices (Outline)
Not expanded in these notes yet.