Advanced Programming Concepts Study Dashboard
Welcome! Your exam is on 4th October. Let's get you prepared.
Syllabus Weightage Breakdown
This chart shows the distribution of marks across the major sections of your syllabus. Focus your time accordingly, paying special attention to the high-weightage areas like Java Core and the Spring Framework ecosystem.
β High-Priority Topics
These topics are frequently asked, complex, and carry significant weightage. Ensure you have a strong command of them.
-
β
Microservices Architecture
Understand concepts like Gateway, Config Server, and Circuit Breaker.
-
β
Java Concurrency
Master Threads, `volatile`, and Synchronization. Virtual Threads are a new, important addition.
-
β
Spring Dependency Injection & IoC
This is the absolute core of the Spring framework. Know the theory and implementation.
-
β
Hibernate Relationships
One-to-Many and Many-to-Many mappings are classic exam questions.
Exception Handling
An exception is an event that disrupts the normal flow of the program. It's an object which is thrown at runtime. Exception Handling is a mechanism to handle runtime errors such as ClassNotFoundException, IOException, SQLException, etc.
Analogy: Think of cooking. You have a recipe (your program's code). An exception is like suddenly running out of an ingredient. Good exception handling is your backup planβlike knowing you can substitute salt with soy sauceβso you don't have to abandon the entire meal.
Checked vs. Unchecked Exceptions
- Checked Exceptions: These are exceptions that are checked at compile-time (e.g., `IOException`, `SQLException`). The compiler forces you to handle them using `try-catch` or by declaring them with the `throws` keyword.
- Unchecked Exceptions (Runtime Exceptions): These are not checked at compile-time (e.g., `NullPointerException`, `ArrayIndexOutOfBoundsException`). They usually indicate a programming error.
The `try-catch-finally` Block
public void readFile(String fileName) {
FileReader reader = null;
try {
reader = new FileReader(fileName);
// Code to read the file
System.out.println("File opened successfully.");
} catch (FileNotFoundException e) {
System.err.println("Error: File not found - " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
System.out.println("File reader closed.");
} catch (IOException e) {
System.err.println("Failed to close reader: " + e.getMessage());
}
}
}
}
π Exam-Ready Notes
- Hierarchy: `Throwable` -> `Exception` & `Error`. `Exception` -> `RuntimeException` (Unchecked) & other exceptions (Checked).
- `finally` block: Always executes, whether an exception is thrown or not. Used for cleanup code (e.g., closing connections, files).
- `throw` vs. `throws`: `throw` is used to manually throw an exception. `throws` is used in a method signature to declare that it might throw certain checked exceptions.
- Try-with-resources: A cleaner way to handle resources that implement `AutoCloseable` (like file streams). It automatically closes the resources. This is a very important topic.
Lambda Expressions
A lambda expression is a short block of code which takes in parameters and returns a value. They are similar to methods, but they do not need a name and they can be implemented right in the body of a method. They are essential for functional programming in Java.
Analogy: Think of it as a disposable, unnamed helper. Instead of hiring a full-time named employee (a method) for a one-time task, you just give quick, on-the-spot instructions to a temp worker (a lambda) to get the job done.
Syntax and Usage
The basic syntax is `(parameters) -> { body; }`. They are used to implement functional interfaces (interfaces with a single abstract method).
import java.util.Arrays;
import java.util.List;
public class LambdaExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
// Old way: Anonymous class
/*
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
*/
// New way: Lambda Expression
names.sort((String a, String b) -> a.compareTo(b));
// Or even more concisely
names.sort(String::compareTo); // Method Reference
// Using lambdas with streams
names.stream()
.filter(s -> s.startsWith("a"))
.forEach(System.out::println); // prints "anna"
}
}
π Exam-Ready Notes
- Functional Interface: An interface with exactly one abstract method. Examples: `Runnable`, `Comparator`, `ActionListener`. The `@FunctionalInterface` annotation is used for compile-time checking.
- Syntax Variations:
- `(a, b) -> a + b` (type inference)
- `s -> System.out.println(s)` (single parameter, no parentheses)
- `() -> 42` (no parameters)
- Method References: A shorthand for a lambda expression that calls a specific method. Syntax: `ClassName::methodName`.
- Use Cases: Collections (`forEach`), Streams API, Concurrency (`Runnable`).
Annotations
Annotations are a form of metadata, they provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate. They are widely used by frameworks like Spring and Hibernate.
Analogy: Annotations are like sticky notes you put on your code. A sticky note saying "Urgent" on a document doesn't change the document's text, but it tells the person handling it (the compiler or framework) how to treat it.
Common Built-in Annotations
- `@Override`: Informs the compiler that the element is meant to override an element declared in a superclass.
- `@Deprecated`: Marks that the element is deprecated and should no longer be used.
- `@SuppressWarnings`: Instructs the compiler to suppress specific warnings it would otherwise generate.
- `@FunctionalInterface`: Indicates that an interface type declaration is intended to be a functional interface.
Creating Custom Annotations
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 1. Define the annotation
@Retention(RetentionPolicy.RUNTIME) // Available at runtime through reflection
@Target(ElementType.METHOD) // Can only be applied to methods
public @interface ExamImportant {
String value() default "Medium";
int weightage() default 5;
}
// 2. Use the annotation
class StudyTopics {
@ExamImportant(value = "High", weightage = 10)
public void studyConcurrency() {
// ... study logic
}
@ExamImportant
public void studyCollections() {
// ... study logic
}
}
π Exam-Ready Notes
- Meta-Annotations: Annotations used to annotate other annotations.
- `@Retention`: Specifies how long the annotation is kept (SOURCE, CLASS, RUNTIME). `RUNTIME` is needed for processing at runtime.
- `@Target`: Specifies where the annotation can be used (TYPE, METHOD, FIELD, etc.).
- `@Inherited`: The annotation will be inherited by subclasses.
- `@Documented`: The annotation will be included in Javadoc.
- Processing: Annotations are processed by tools or libraries, often using Java Reflection at runtime. This is the foundation of how frameworks like Spring work.
Java Collections Framework
The Collections Framework is a unified architecture for representing and manipulating collections. It provides interfaces (like `List`, `Set`, `Map`) and classes (like `ArrayList`, `HashSet`, `HashMap`).
Key Interfaces
Interface | Description | Common Implementations |
---|---|---|
List | An ordered collection (a sequence). Allows duplicate elements. | `ArrayList`, `LinkedList` |
Set | A collection that contains no duplicate elements. | `HashSet`, `LinkedHashSet`, `TreeSet` |
Queue | A collection used to hold elements prior to processing. Typically orders elements in a FIFO (first-in-first-out) manner. | `LinkedList`, `PriorityQueue` |
Map | An object that maps keys to values. A map cannot contain duplicate keys. | `HashMap`, `LinkedHashMap`, `TreeMap` |
Example: Using HashMap
import java.util.Map;
import java.util.HashMap;
public class MapExample {
public static void main(String[] args) {
Map<String, Integer> studentScores = new HashMap<>();
// Add key-value pairs
studentScores.put("Alice", 95);
studentScores.put("Bob", 88);
studentScores.put("Charlie", 92);
// Retrieve a value
int aliceScore = studentScores.get("Alice");
System.out.println("Alice's Score: " + aliceScore);
// Iterate over the map
for (Map.Entry<String, Integer> entry : studentScores.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
π Exam-Ready Notes
- `ArrayList` vs. `LinkedList`: `ArrayList` is faster for random access (`get(i)`). `LinkedList` is faster for adding/removing elements from the middle.
- `HashSet` vs. `TreeSet`: `HashSet` is faster but offers no ordering. `TreeSet` keeps elements sorted but is slower.
- `HashMap` vs. `TreeMap`: `HashMap` is faster but unordered. `TreeMap` keeps keys sorted.
- Iterator: An object used to loop through collections. Provides `hasNext()`, `next()`, and `remove()` methods. It's the standard way to traverse a collection.
- `Collections` Utility Class: Provides static methods for sorting, searching, reversing, etc., on collections (e.g., `Collections.sort(myList)`).
Concurrency (β High Importance)
Concurrency is the ability of a program to run several parts of itself in parallel. Java provides rich support for concurrency, from basic threads to high-level executor services and the new virtual threads.
Java Memory Model (JMM)
The JMM defines the rules for how threads interact through memory. Each thread has its own private stack (for local variables), but they all share the main memory (the Heap), where objects live. This sharing is what creates visibility and synchronization problems.
Simplified Java Memory Model
Main Memory (Heap)
(Shared Variables / Objects)
Thread 1
(CPU Cache / Stack)
Thread 2
(CPU Cache / Stack)
`volatile` Keyword
The `volatile` keyword guarantees that any write to a volatile variable will be directly written to main memory, and any read will be directly from main memory. This ensures visibility across threads.
Analogy: A `volatile` variable is like a shared public whiteboard. When one person writes on it, everyone else immediately sees the update. A non-volatile variable is like each person having their own private notepad; updates aren't visible to others until explicitly shared.
`synchronized` Keyword
`synchronized` provides a lock mechanism to ensure that only one thread can execute a block of code or a method at a time. It guarantees both visibility and atomicity (the operation is indivisible).
public class Counter {
private int count = 0;
// This method is thread-safe
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
Virtual Threads (Project Loom)
Introduced in newer Java versions, virtual threads are lightweight threads managed by the JVM, not the OS. This allows for creating millions of them, making them ideal for high-throughput concurrent applications, especially those with lots of blocking I/O (like waiting for network requests).
π Exam-Ready Notes
- Creating Threads: Either extend the `Thread` class or implement the `Runnable` interface (preferred).
- Thread States: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
- `volatile` vs. `synchronized`: `volatile` only ensures visibility. `synchronized` ensures visibility AND atomicity (mutual exclusion). Use `volatile` for simple flags, `synchronized` for compound actions (like read-modify-write).
- Deadlock: A situation where two or more threads are blocked forever, waiting for each other.
- Platform vs. Virtual Threads: Platform threads are traditional OS threads (heavyweight). Virtual threads are JVM-managed (lightweight).
I/O Operations & File Handling
Java's I/O (Input/Output) is a powerful mechanism that makes it easy for developers to read and write data. The `java.io` package contains classes for this purpose. Modern I/O is often handled by `java.nio` (New I/O) for better performance.
Reading a File with Try-with-Resources
The `try-with-resources` statement is the recommended way to handle resources like streams, as it ensures they are closed automatically, preventing resource leaks.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileExample {
public void readFile(String path) {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("An error occurred while reading the file: " + e.getMessage());
}
}
}
Character vs. Byte Streams
- Byte Streams (`InputStream`, `OutputStream`): Used for handling I/O of raw binary data (like images, videos). They read/write data one byte at a time.
- Character Streams (`Reader`, `Writer`): Used for handling I/O of character data (text files). They automatically handle character encoding conversion.
π Exam-Ready Notes
- `File` class: Represents a file or directory path. Used for operations like creating, deleting, renaming files. It does not handle content.
- Decorator Pattern: Java I/O heavily uses the decorator pattern. For example, `BufferedReader` adds buffering functionality to another `Reader` (`FileReader`), improving performance.
- Serialization: The process of converting an object into a byte stream to store it or transmit it over a network. The receiving end can then deserialize it back into an object. An object must implement the `Serializable` interface.
- Java NIO (`java.nio`): Provides more efficient I/O operations using concepts like Channels, Buffers, and Selectors. It's more complex but performs better for high-volume applications.
Database Access (JDBC)
JDBC (Java Database Connectivity) is a standard Java API for connecting and executing queries with a database. It's part of the standard Java SE platform.
The 5 Steps of JDBC
- Load and register the driver: `Class.forName("com.mysql.cj.jdbc.Driver");`
- Establish a connection: `Connection con = DriverManager.getConnection(url, user, password);`
- Create a statement: `Statement stmt = con.createStatement();` or `PreparedStatement pstmt = ...`
- Execute the query: `ResultSet rs = stmt.executeQuery("SELECT * FROM students");`
- Process the result set and close resources: Loop through `rs`, then close `rs`, `stmt`, and `con`.
`Statement` vs. `PreparedStatement`
This is a classic and very important exam question. Always prefer `PreparedStatement`.
- `PreparedStatement` is pre-compiled: The SQL query is compiled once by the database, leading to better performance for queries that are executed multiple times.
- `PreparedStatement` prevents SQL Injection: It automatically escapes special characters, protecting your application from SQL injection attacks.
// Using PreparedStatement to prevent SQL injection
String query = "SELECT * FROM users WHERE username = ? AND password = ?";
try (Connection con = ...;
PreparedStatement pstmt = con.prepareStatement(query)) {
pstmt.setString(1, "admin"); // Set the first '?'
pstmt.setString(2, "password123"); // Set the second '?'
try (ResultSet rs = pstmt.executeQuery()) {
// Process results...
}
} catch (SQLException e) {
e.printStackTrace();
}
π Exam-Ready Notes
- `ResultSet`: An object that holds the data retrieved from a database after you execute a SQL query. It's a cursor that points to one row of data. Use `rs.next()` to move to the next row.
- JDBC Transactions: A transaction is a sequence of operations performed as a single logical unit of work. Key methods on the `Connection` object:
- `setAutoCommit(false)`: Start a transaction.
- `commit()`: Make changes permanent.
- `rollback()`: Undo changes.
- `DriverManager`: A class that manages a list of database drivers. The `getConnection()` method is used to establish a connection.
Build Tools (Maven)
Maven is a powerful project management and build automation tool. It simplifies the build process by managing dependencies, compiling source code, packaging, and more, based on a Project Object Model (POM).
The POM (`pom.xml`)
The `pom.xml` file is the heart of a Maven project. It contains project information and configuration details used by Maven to build the project. Key sections include:
- `groupId`, `artifactId`, `version`: The project's unique coordinates.
- `
`: A list of external libraries (JARs) your project needs. Maven automatically downloads these from a central repository. - `
`: Contains information about how to build the project, including plugins.
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Maven Build Lifecycle
The build lifecycle is a sequence of phases. When you run a phase, Maven executes all preceding phases as well. The default lifecycle includes:
- `validate`: validate the project is correct and all necessary information is available.
- `compile`: compile the source code of the project.
- `test`: run tests using a suitable unit testing framework.
- `package`: take the compiled code and package it in its distributable format, such as a JAR.
- `install`: install the package into the local repository, for use as a dependency in other projects locally.
- `deploy`: done in an integration or release environment, copies the final package to the remote repository.
π Exam-Ready Notes
- Convention over Configuration: Maven follows standard conventions (e.g., source code is in `src/main/java`), which reduces the amount of configuration needed.
- Dependency Management: Maven's key feature. It handles transitive dependencies automatically (dependencies of your dependencies).
- Repository: A location where Maven stores project artifacts. There are three types: local (on your machine), central (public repository), and remote (private company repository).
- Common Commands: `mvn clean install`, `mvn package`, `mvn test`.
Spring Core (β High Importance)
The Spring Framework is a powerful, lightweight framework for developing Java applications. The core module provides the fundamental parts of the framework, including the IoC Container and Dependency Injection.
Inversion of Control (IoC) and Dependency Injection (DI)
Analogy: Think of building a car.
Without IoC: You, the `Car` class, are responsible for creating your own engine: `Engine engine = new Engine();`. You control the creation.
With IoC: You just declare that you need an engine: `private Engine engine;`. An external assembler (the Spring IoC Container) reads your blueprint and gives ("injects") a pre-built engine to you. The control of creating the engine has been invertedβfrom you to the framework. This process of giving the engine is called Dependency Injection.
Dependency Injection Flow
Types of Dependency Injection
- Constructor Injection (Recommended): Dependencies are provided as constructor arguments. This ensures the object is always in a valid state.
- Setter Injection: The container calls setter methods on your bean after it has been instantiated.
- Field Injection (Avoid): Dependencies are injected directly into fields using `@Autowired`. This is convenient but makes testing harder.
@Component
public class NotificationService {
private final EmailService emailService;
// Constructor Injection
@Autowired
public NotificationService(EmailService emailService) {
this.emailService = emailService;
}
public void sendNotification(String to, String message) {
emailService.send(to, "Notification", message);
}
}
@Component
public class EmailService {
public void send(String to, String subject, String body) {
// ... logic to send email
System.out.println("Email sent to " + to);
}
}
π Exam-Ready Notes
- Spring IoC Container: The core of Spring. It creates objects, wires them together, configures them, and manages their complete lifecycle. Also known as the `ApplicationContext`.
- Bean: An object that is instantiated, assembled, and otherwise managed by the Spring IoC container.
- Configuration: How you tell the container what beans to create and how to wire them. Can be done via XML, Annotations (`@Component`, `@Configuration`), or Java code. Annotation-based is the modern standard.
- Stereotype Annotations: `@Component` (generic), `@Service` (for business logic), `@Repository` (for data access), `@Controller` (for presentation layer).
- Spring Bean Scopes: Defines the lifecycle of a bean.
- `singleton` (default): Only one instance of the bean per container.
- `prototype`: A new instance is created every time it's requested.
- `request`, `session`, `application`: Scopes for web applications.
Spring MVC
Spring MVC (Model-View-Controller) is a framework for building web applications. It provides a clean separation of concerns between the business logic, data, and presentation layers.
MVC Architecture & Flow
This diagram shows how a request is processed in Spring MVC. Understanding this flow is critical.
Spring MVC Request Flow
- The `DispatcherServlet` receives the request.
- It consults the `HandlerMapping` (not shown) to find the appropriate `Controller`.
- The `Controller` processes the request, interacts with services, and returns a model and a logical view name.
- The `DispatcherServlet` sends the view name to the `ViewResolver`.
- The `ViewResolver` finds the actual `View` (e.g., a JSP file).
- The `View` is rendered with the model data and returned to the client.
Example Controller
@Controller
public class GreetingController {
@GetMapping("/greeting") // Maps HTTP GET requests for /greeting to this method
public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name); // Add data to the model
return "greeting"; // Return the logical view name
}
}
π Exam-Ready Notes
- `DispatcherServlet`: The front controller that handles all incoming requests and dispatches them to the correct handlers.
- `@Controller` vs. `@RestController`: `@Controller` is used for traditional Spring MVC, where methods return a view name. `@RestController` combines `@Controller` and `@ResponseBody`, and is used for building REST APIs where methods return data (like JSON) directly.
- Request Mapping Annotations: `@RequestMapping`, `@GetMapping`, `@PostMapping`, `@PutMapping`, `@DeleteMapping`.
- Data Binding Annotations: `@RequestParam` (for URL parameters), `@PathVariable` (for parts of the URL path), `@RequestBody` (for the request body, e.g., JSON).
- JSP (JavaServer Pages): A technology to create dynamic, platform-independent web pages. It allows embedding Java code into HTML pages, which is then rendered by the server.
Hibernate
Hibernate is an Object-Relational Mapping (ORM) framework. It solves the problem of "impedance mismatch" between object-oriented Java code and relational databases. It lets you work with database tables as if they were plain Java objects.
Entity and Relationships (β High Importance)
An Entity is a simple POJO (Plain Old Java Object) that is mapped to a database table. Annotations like `@Entity`, `@Table`, `@Id`, `@Column` are used for mapping.
// Example of a One-to-Many relationship
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Book> books = new ArrayList<>();
// ... getters and setters
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
// ... getters and setters
}
Entity Lifecycle States
An entity instance can be in one of three states:
- Transient: The object has just been created with `new` and is not associated with any Hibernate session or database row.
- Persistent: The object is associated with a Hibernate session. Any changes made to it will be automatically detected and saved to the database when the transaction is committed.
- Detached: The object was once persistent, but the session it was associated with has been closed.
π Exam-Ready Notes
- ORM: Object-Relational Mapping. A technique for converting data between incompatible type systems in object-oriented programming languages and relational databases.
- `SessionFactory` & `Session`: `SessionFactory` is a heavyweight, thread-safe object created once per application. It creates `Session` objects. The `Session` is a lightweight, single-threaded object that represents a conversation with the database.
- Relationship Annotations: `@OneToOne`, `@OneToMany`, `@ManyToOne`, `@ManyToMany`. Pay attention to attributes like `cascade`, `fetch`, and `mappedBy`.
- `FetchType.LAZY` vs. `FetchType.EAGER`: LAZY (preferred) loads the related entities only when they are accessed. EAGER loads them immediately with the parent entity. EAGER can lead to performance problems.
- Transactions: Hibernate operations must be performed within a transaction. The `Session` provides methods to begin, commit, and roll back transactions.
Spring Boot
Spring Boot is an opinionated extension of the Spring platform that simplifies the creation of stand-alone, production-grade Spring-based applications. It removes most of the boilerplate configuration required for Spring.
Key Features
- Auto-configuration: Spring Boot automatically configures your application based on the JAR dependencies you have added. For example, if it sees `spring-boot-starter-web` on the classpath, it automatically configures Tomcat and Spring MVC.
- Starters: Convenient dependency descriptors that you can include in your application. They bundle common dependencies together. Examples: `spring-boot-starter-web`, `spring-boot-starter-data-jpa`.
- Embedded Server: Spring Boot applications come with an embedded server (like Tomcat, Jetty, or Undertow) by default, so you don't need to deploy WAR files. You can just run the main method.
- Actuators: Provides production-ready features to monitor and manage your application (e.g., health checks, metrics, environment info) via HTTP endpoints.
@SpringBootApplication // Combines @Configuration, @EnableAutoConfiguration, and @ComponentScan
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
π Exam-Ready Notes
- Goal: To get you up and running as quickly as possible with minimal configuration. It favors convention over configuration.
- `@SpringBootApplication`: The main annotation that enables all of Spring Boot's magic.
- `application.properties` / `application.yml`: Centralized place for application configuration, such as database connection details, server port, etc.
- Spring Boot vs. Spring: Spring Boot is not a replacement for Spring. It's a tool to make working with the Spring Framework easier and faster.
Spring Data
Spring Data's mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store. It makes it easier to use data access technologies, relational and non-relational databases, map-reduce frameworks, and cloud-based data services.
Spring Data JPA
Spring Data JPA is not a JPA provider itself (like Hibernate). It's a library that adds a layer of abstraction on top of a JPA provider, making data access even easier. Its most powerful feature is the ability to create repository implementations automatically, at runtime, from a repository interface.
// 1. Define an Entity (same as in Hibernate)
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
private String email;
// ... getters and setters
}
// 2. Create a Repository Interface
public interface UserRepository extends JpaRepository<User, Long> {
// Spring Data JPA will automatically create the implementation for this method!
// It derives the query from the method name.
User findByUsername(String username);
List<User> findByEmailContainingIgnoreCase(String emailPart);
}
// 3. Use it in a Service
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void registerUser(User user) {
if (userRepository.findByUsername(user.getUsername()) == null) {
userRepository.save(user);
}
}
}
π Exam-Ready Notes
- Repository Abstraction: The core idea. You define an interface, and Spring Data provides the implementation for common CRUD (Create, Read, Update, Delete) operations automatically.
- Common Interfaces: `CrudRepository` (basic CRUD), `PagingAndSortingRepository` (adds pagination and sorting), `JpaRepository` (adds JPA-specific features like flushing).
- Query Derivation: Spring Data can derive queries from the method names in your repository interface (e.g., `findByNameAndAge`).
- `@Query` Annotation: For complex queries that cannot be derived from method names, you can use the `@Query` annotation to write custom JPQL or native SQL queries.
- Spring Data MongoDB: Provides similar repository abstractions for working with MongoDB, using `MongoRepository`. The concepts are very similar to JPA.
Microservices (β High Importance)
Microservice architecture is an approach to developing a single application as a suite of small, independently deployable services. Each service runs in its own process and communicates with lightweight mechanisms, often an HTTP resource API. Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems.
Key Spring Cloud Components
Spring Cloud Gateway
Provides a single entry point for all clients. It handles routing, security, monitoring, and resiliency for all microservices. Analogy: The main entrance and security desk of an office building.
Spring Cloud Config
Provides centralized external configuration management. It allows you to manage configuration for all services in one place (usually a Git repository) without redeploying them. Analogy: A central notice board for the entire office building.
Spring Cloud Circuit Breaker
(e.g., Resilience4j) A pattern to prevent a network or service failure from cascading to other services. If a service is failing, the circuit breaker "opens" and subsequent calls fail immediately, rather than waiting and consuming resources. Analogy: An electrical circuit breaker that trips to prevent damage during a power surge.
Spring Cloud OpenFeign
A declarative REST client. It makes writing web service clients easier. You just create an interface and annotate it, and Feign provides the implementation. Analogy: An internal phone directory that lets you call another department by just knowing their name, without needing their exact desk number.
π Exam-Ready Notes
- Monolith vs. Microservices: Monolith is a single, unified application. Microservices are small, independent services. Know the pros and cons (e.g., microservices are scalable and flexible but complex to manage).
- Service Discovery (e.g., Eureka): How services find each other in a dynamic environment. Not explicitly in syllabus but related to Gateway.
- Challenges: Distributed transactions, data consistency, network latency, monitoring, and logging are all major challenges in a microservices architecture.
Testing (10%)
Testing is a critical part of the software development lifecycle. It ensures that your code works as expected and helps prevent bugs in production.
JUnit
JUnit is the most popular unit testing framework for Java. A unit test checks a single "unit" of work, typically a method, in isolation.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
@Test // Marks this method as a test case
void testAddition() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 should equal 5");
}
@Test
void testDivisionByZero() {
Calculator calculator = new Calculator();
// Asserts that executing the lambda will throw an ArithmeticException
assertThrows(ArithmeticException.class, () -> {
calculator.divide(1, 0);
});
}
}
Spring Boot provides excellent testing support with `@SpringBootTest`, which loads the entire application context for integration tests, and `@WebMvcTest` for testing web controllers in isolation.
JMeter
Apache JMeter is an open-source tool designed for load testing and performance measurement. It's not a unit testing tool. It's used to simulate a heavy load from a number of users on a server, network, or object to test its strength or to analyze overall performance under different load types.
π Exam-Ready Notes
- JUnit Annotations: `@Test`, `@BeforeEach` (runs before each test), `@AfterEach` (runs after each test), `@BeforeAll` (runs once before all tests), `@AfterAll` (runs once after all tests).
- Assertions: Static methods from `org.junit.jupiter.api.Assertions` class used to check conditions (e.g., `assertEquals`, `assertTrue`, `assertNotNull`).
- Mocking: Creating "fake" objects that simulate the behavior of real objects. Frameworks like Mockito are used to isolate the unit under test from its dependencies.
- JMeter vs. JUnit: JUnit is for unit/integration testing (functional correctness). JMeter is for performance/load testing (non-functional requirements like speed and stability).
π― Practice Zone
Test your knowledge with these questions. Try to answer them first before revealing the solution.
Multiple Choice Questions (MCQs)
1. Which of the following is NOT a core principle of the Spring Framework?
a) Inversion of Control (IoC)
b) Aspect-Oriented Programming (AOP)
c) Global Variable Management
d) Dependency Injection (DI)
2. What is the primary advantage of using a `PreparedStatement` over a `Statement` in JDBC?
a) It supports more SQL data types.
b) It prevents SQL Injection attacks.
c) It automatically closes the connection.
d) It can execute multiple queries at once.
3. A Java interface with exactly one abstract method is known as a:
a) Marker Interface
b) Abstract Interface
c) Functional Interface
d) Singleton Interface
4. In the Java Memory Model, which part is shared among all threads?
a) Thread Stack
b) Program Counter
c) Heap Memory
d) CPU Registers
5. Which Spring Boot feature attempts to automatically configure your application based on the JAR dependencies present?
a) Starters
b) Actuator
c) Auto-configuration
d) Embedded Server
5-Mark Questions (Short Answer / Coding)
1. Explain the difference between `volatile` and `synchronized` in Java concurrency. Provide a use case for each.
2. Write a Java Lambda expression to sort a list of `String` objects by their length in descending order.
3. What is the role of the `DispatcherServlet` in Spring MVC? Briefly explain its workflow.
10-Mark Questions (Long Answer / Coding)
1. Explain the concepts of Inversion of Control (IoC) and Dependency Injection (DI) in Spring. Describe the three types of DI and explain why constructor injection is generally preferred. Provide a complete Java code example using Spring annotations to demonstrate DI between a `CustomerService` and a `CustomerRepository`.
2. Imagine you are building an application with microservices for an e-commerce platform: a `Product-Service` and an `Order-Service`. Explain how Spring Cloud Gateway, Config Server, and Circuit Breaker would be used in this architecture. Draw a simple block diagram to illustrate the flow.