Web Development
Spring Boot Questions
Comprehensive Spring Boot guide covering Introduction, Architecture, Configuration, and IoC/DI. Each answer is technically rigorous for professional interviews.
Introduction & Basics10
Spring Boot is an extension of the Spring framework that aims to simplify the development, configuration, and deployment of Spring applications. It follows an 'opinionated' approach by providing defaults for code and annotation configuration to quick-start new projects, significantly reducing the amount of boilerplate code and complex XML configurations.
The primary advantages include auto-configuration, which reduces manual setup; embedded servers like Tomcat, which eliminate the need for external WAR deployment; and 'Starter' dependencies that simplify build configurations. Additionally, it offers production-ready features like health checks and metrics via Actuator, which were complex to implement in the standard Spring framework.
Auto-configuration is a core feature where Spring Boot automatically configures your application based on the dependencies present on the classpath. For example, if 'spring-boot-starter-data-jpa' is detected, Spring Boot will automatically attempt to configure a DataSource and an Entity Manager, saving the developer from writing repetitive configuration code.
Internally, Spring Boot uses the @EnableAutoConfiguration annotation, which leverages the SpringFactoriesLoader mechanism to look for 'spring.factories' files in the META-INF directory of your dependencies. It evaluates @Conditional annotations, such as @ConditionalOnClass or @ConditionalOnProperty, to decide whether a specific configuration bean should be instantiated and registered in the application context.
The @SpringBootApplication is a convenience annotation that combines three essential annotations: @Configuration (marking the class as a source of bean definitions), @EnableAutoConfiguration (enabling the automatic configuration mechanism), and @ComponentScan (telling Spring to scan for components, services, and controllers in the current package and its sub-packages).
Spring Boot Starters are a set of convenient dependency descriptors that you can include in your application to get all the necessary libraries for a specific feature. Important starters include 'spring-boot-starter-web' for RESTful services, 'spring-boot-starter-data-jpa' for database connectivity, 'spring-boot-starter-security' for authentication, and 'spring-boot-starter-test' for unit and integration testing frameworks.
Spring is the core IoC container and dependency injection framework. Spring MVC is a web framework built on the Servlet API that follows the Model-View-Controller pattern. Spring Boot is a wrapper around these that provides auto-configuration, embedded servers, and starter dependencies to make building production-grade applications much faster and easier.
Convention over configuration is a software design paradigm that seeks to decrease the number of decisions that a developer has to make without necessarily losing flexibility. In Spring Boot, this means providing sensible defaults (like Port 8080 and H2 database auto-wiring) so that the application works out of the box with minimal manual setup.
An embedded server is a web server bundled within the application's JAR file, meaning you don't need to install a standalone server (like a separate Tomcat instance) on the target machine. Spring Boot supports Apache Tomcat (the default), Jetty, and Undertow, allowing the application to run as a simple Java process.
You can create a Spring Boot application using the Spring Initializr (start.spring.io) web interface, the Spring Tool Suite (STS) IDE, or CLI tools. After selecting the desired Java version and dependencies, the tool generates a Maven or Gradle project structure with the @SpringBootApplication entry point ready for development.
Architecture & Configuration15
Spring Boot architecture typically follows a four-layered structure: 1. Presentation Layer (Controllers), which handles HTTP requests; 2. Business Layer (Services), where logic is processed; 3. Persistence Layer (Repositories), which manages database interaction; and 4. Database Layer (Actual SQL/NoSQL store). This separation of concerns ensures that the application is modular, testable, and maintainable.
Both are used for externalizing configuration, but they differ in format. 'application.properties' uses a flat key-value pair format (server.port=8080), while 'application.yml' uses a hierarchical, indented YAML format (server: port: 8080). YAML is generally preferred for complex configurations because it reduces repetition and is more readable for nested properties.
Spring Boot uses a specific hierarchy for loading properties to allow overrides. The order (from lowest to highest priority) is: 1. Default properties in code, 2. application.properties/yml inside the JAR, 3. External application.properties/yml outside the JAR, 4. OS environment variables, 5. Java System properties, and 6. Command-line arguments. The last one always wins.
Configuration can be externalized using various methods such as properties files, YAML files, environment variables, and command-line arguments. This allows the same application code to run in different environments (dev, test, prod) without modification, simply by changing the external configuration values associated with the specific environment.
The @Value annotation is used to inject values into fields in Spring-managed beans from property files, environment variables, or other expressions. It supports SpEL (Spring Expression Language) and can provide default values using the syntax '@Value("${property.name:default_value}")', making it highly flexible for simple configuration injection.
The @ConfigurationProperties annotation is used to bind external properties to a strongly typed Java object. It is better than @Value for grouping related properties (e.g., all 'mail.*' properties). It supports hierarchical mapping, relaxed binding, and JSR-303 bean validation, making it the preferred choice for complex configuration management.
@Value is suitable for injecting individual standalone values and supports SpEL, but it doesn't support relaxed binding or nested properties. @ConfigurationProperties is designed for bulk property injection into an object, supports relaxed binding (e.g., mapping 'server_port' to 'serverPort'), and is easier to validate and maintain for large sets of configurations.
Spring Profiles provide a way to segregate parts of your application configuration and make it available only in certain environments. For example, you can have a 'dev' profile that uses an H2 in-memory database and a 'prod' profile that uses an external PostgreSQL database, ensuring environment-specific behavior without changing code.
Profiles can be activated in several ways: 1. In 'application.properties' using 'spring.profiles.active=dev'; 2. Via command-line arguments using '--spring.profiles.active=prod'; 3. Through OS environment variables; or 4. Programmatically using the ConfigurableEnvironment API. You can also activate multiple profiles simultaneously using a comma-separated list.
The @Profile annotation is used to conditionally register a Spring bean or configuration class only when a specific profile is active. For example, '@Profile("dev")' on a bean definition ensures that the bean is only loaded into the Spring container when the application is started with the 'dev' profile.
The @PropertySource annotation provides a mechanism for adding a custom property file to Spring's Environment. While Spring Boot automatically loads 'application.properties', @PropertySource is useful if you have custom configuration files located in non-standard locations that need to be parsed and made available to the application context.
You can create environment-specific files using the naming convention 'application-{profile}.properties'. For example, 'application-dev.properties' and 'application-prod.properties'. When you activate the 'dev' profile, Spring Boot will load 'application.properties' first and then override those values with the ones found in the 'application-dev' file.
These are environment-specific files. 'application-dev.properties' usually contains settings for local development, such as debug logging and local databases. 'application-prod.properties' contains production-grade settings like strict security, connection pooling for a cloud database, and minimized logging to prevent performance overhead on the live server.
You can override any property at startup by passing it as a command-line argument using the double-dash syntax: 'java -jar app.jar --server.port=9090'. Spring Boot places command-line arguments at the highest level of its property hierarchy, ensuring they take precedence over properties defined inside the JAR file.
Spring Boot DevTools is a set of tools intended to improve the developer experience. Its primary features include Automatic Restart (whenever files on the classpath change), LiveReload (automatically refreshing the browser), and the disabling of template caching (so changes to HTML/CSS are reflected immediately), significantly speeding up the development cycle.
Spring IOC & Dependency Injection15
IoC is a design principle in which the control of object creation and lifecycle management is transferred from the application code to a container or framework. Instead of the programmer manually instantiating classes using 'new', the Spring container manages the 'wiring' and lifecycle of objects (beans), leading to loosely coupled code.
Dependency Injection (DI) is a specific implementation of IoC where the container 'injects' the required dependencies into a class at runtime. This allows a class to remain independent of how its dependencies are created or managed, facilitating easier unit testing (by injecting mocks) and better separation of concerns across the application layers.
The three primary types of Dependency Injection in Spring are: 1. Constructor Injection (dependencies passed via constructor), 2. Setter Injection (dependencies passed via setter methods), and 3. Field Injection (dependencies injected directly into fields using @Autowired). Each has its own use case, with constructor injection being the most favored in modern Spring development.
Constructor injection ensures that required dependencies are provided at the time of object creation, making the bean immutable. Setter injection allows for optional dependencies that can be changed later. Field injection uses reflection to inject values directly into private fields, which is the easiest to write but makes unit testing harder without a Spring context.
Constructor injection is the recommended approach for several reasons: it allows dependencies to be final (immutable), it prevents 'null' pointer exceptions by ensuring all required components are present at instantiation, and it makes the code easier to test without needing complex reflection-based mock injection in unit tests.
The @Autowired annotation is used to tell Spring to automatically inject a dependency into a bean. It can be applied to constructors, methods, or fields. Spring resolves the dependency by looking for a matching bean in the application context based on the type; if multiple beans of the same type exist, it may require @Qualifier.
The @Component annotation marks a Java class as a Spring bean. During component scanning, Spring detects classes annotated with @Component, instantiates them, and adds them to the application context. It is a generic stereotype for any Spring-managed component, while others like @Service or @Repository are more specific specializations.
@Component is the general-purpose stereotype. @Repository is used for the persistence layer and adds automatic exception translation. @Service is used for business logic to provide semantic meaning. @Controller is used for web layers to handle HTTP requests. While they are functionally similar (all are beans), using the specific one provides better architectural clarity.
The @Bean annotation is used at the method level, typically within a @Configuration class, to explicitly define a bean and add it to the Spring context. Unlike @Component (which is class-level), @Bean is useful for integrating third-party libraries where you cannot modify the source code to add annotations.
@Component is used for 'auto-detection' through classpath scanning and is placed on the class itself. @Bean is used for 'explicit' configuration and is placed on a method inside a configuration class. Use @Component for your own classes and @Bean when you need to configure beans from external libraries.
The @Qualifier annotation is used when there are multiple beans of the same type and Spring cannot decide which one to inject. By providing a specific name to @Qualifier (e.g., @Qualifier("mySpecificService")), you help Spring resolve the ambiguity and inject the exact bean implementation you intended.
The @Primary annotation is used to designate a default bean when multiple beans of the same type are available. If no @Qualifier is specified at the injection point, Spring will automatically choose the bean marked with @Primary. It is a simpler alternative to @Qualifier when one implementation is the 'standard' choice.
Circular dependency occurs when Bean A depends on Bean B, and Bean B depends back on Bean A, creating a loop that prevents Spring from finishing the injection. You can resolve this by using setter injection instead of constructor injection, or by using the @Lazy annotation to delay the initialization of one of the beans.
Bean scopes define the lifecycle and visibility of a bean within the container. The five standard scopes are: 1. Singleton (one instance per container), 2. Prototype (new instance every time requested), 3. Request (one per HTTP request), 4. Session (one per HTTP session), and 5. Application (one per ServletContext).
Singleton is the default scope where Spring creates only one instance of the bean and shares it across the entire application. Prototype scope creates a brand new instance every single time the bean is requested from the container. Use Singleton for stateless services and Prototype for beans that maintain state for a specific user or thread.
Spring AOP5
AOP is a programming paradigm that aims to increase modularity by allowing the separation of 'cross-cutting concerns.' It allows you to add behavior (like logging, security, or transaction management) to existing code without modifying the actual business logic, keeping the core code clean and focused on its primary task.
Cross-cutting concerns are aspects of a program that affect multiple modules but do not belong specifically to the business logic of any single one. Common examples include logging, performance monitoring, security checks, and transaction management, which often 'cut across' the entire application architecture.
An 'Aspect' is the module containing the cross-cutting logic. 'Advice' is the specific action taken (the 'what'). 'JoinPoint' is a point during the execution of the program (like a method call). 'Pointcut' is a set of one or more JoinPoints where an Advice should be applied (the 'where').
The @Aspect annotation marks a Java class as an aspect, enabling the Spring container to recognize it and apply the advice defined within it to the target beans. To make it work in Spring Boot, you also need to ensure that '@EnableAspectJAutoProxy' is active (though Boot often enables this by default if 'spring-boot-starter-aop' is present).
'Before' runs before the method call. 'After' runs regardless of outcome. 'AfterReturning' runs only if the method completes successfully. 'AfterThrowing' runs only if an exception is thrown. 'Around' is the most powerful advice, as it can control whether the target method even executes and can modify its return value.
Spring MVC20
Spring MVC is a web framework built on the Servlet API that implements the Model-View-Controller design pattern. It provides a robust set of tools to handle HTTP requests, map URLs to Java methods, process form data, and render views (like HTML or JSON), making it the foundation for most Java web applications.
The flow starts with the DispatcherServlet receiving a request. It consults the HandlerMapping to find the right Controller. The Controller processes the business logic (often via a Service) and returns a Model and a View name. The ViewResolver then finds the actual view template, and the final HTML/JSON is sent back to the client.
DispatcherServlet is the 'Front Controller' of a Spring MVC application. It is responsible for receiving every incoming HTTP request and orchestrating the entire request-response lifecycle. It delegates tasks like routing to HandlerMappings, processing to Controllers, and rendering to ViewResolvers, serving as the central hub of the web layer.
The @Controller annotation is a specialization of @Component used to mark a class as a web request handler. It is typically used in traditional web applications that return views (like JSP or Thymeleaf). It works in conjunction with @RequestMapping to map web requests to specific Java methods for processing.
@RestController is a convenience annotation that combines @Controller and @ResponseBody. While a standard @Controller returns a view name to be resolved, a @RestController returns the data itself (serialized as JSON or XML) directly in the HTTP response body, making it the ideal choice for building RESTful APIs.
The @RequestMapping annotation is used to map web requests to specific handler classes and methods. It is highly versatile, allowing you to specify the URL path, HTTP method (GET, POST, etc.), headers, and produced/consumed media types, forming the core of the request routing logic in Spring MVC.
These are composed annotations that serve as shortcuts for @RequestMapping with a specific HTTP method. For example, @GetMapping is equivalent to @RequestMapping(method = RequestMethod.GET). They improve code readability and follow RESTful principles by explicitly stating the intent of the endpoint in the annotation name.
The @PathVariable annotation is used to extract values directly from the URI path. For instance, in a mapping like '/users/{id}', @PathVariable('id') allows you to bind the value of '{id}' from the URL to a method parameter, which is essential for creating dynamic RESTful endpoints.
The @RequestParam annotation is used to extract query parameters from the request URL (e.g., '/search?name=john'). It allows you to bind these parameters to method arguments and provides options for default values and mandatory/optional requirements, making it ideal for filtering and search logic.
@PathVariable extracts values from the URI path itself (e.g., /users/101), making it suitable for identifying specific resources. @RequestParam extracts values from the query string (e.g., /users?status=active), which is better suited for optional parameters like sorting, filtering, or pagination in a REST API.
The @RequestBody annotation is used to map the entire HTTP request body (usually JSON or XML) to a Java object. Spring uses HttpMessageConverters to automatically deserialize the incoming payload into a POJO, which is the standard way to handle POST and PUT data in RESTful services.
The @ResponseBody annotation tells Spring that the return value of a method should be bound directly to the web response body rather than being interpreted as a view name. When using @RestController, this annotation is automatically applied to all methods, facilitating JSON/XML data exchange.
ResponseEntity represents the entire HTTP response, including the status code, headers, and the body. It allows developers to have full control over the response sent to the client, such as returning a '201 Created' status for a successful POST or custom headers for security/caching.
HttpStatus is a Java enum in Spring that represents all standard HTTP status codes defined by RFCs. Instead of hardcoding magic numbers like 200 or 404, developers use HttpStatus.OK or HttpStatus.NOT_FOUND to make the code more readable, maintainable, and less prone to errors.
You can return different status codes by using either the ResponseEntity class (e.g., new ResponseEntity<>(body, HttpStatus.CREATED)) or the @ResponseStatus annotation on a method or custom exception class. Using ResponseEntity is generally more dynamic as it allows for logic-based status selection within the method.
Content Negotiation is the process of determining which media type (JSON, XML, HTML, etc.) should be sent to the client based on their request. Spring examines the 'Accept' header or file extensions to select the appropriate HttpMessageConverter to serialize the response accordingly.
Servlets are the low-level Java components that handle web requests; Spring MVC's DispatcherServlet is itself a servlet. JSPs are a legacy view technology for generating dynamic HTML. In Spring MVC, the DispatcherServlet delegates to controllers, which may eventually forward the request to a JSP for rendering.
The 'Model' is an interface used to pass data to the view. 'ModelMap' is a specific implementation of a Map for the same purpose. 'ModelAndView' is a container that holds both the model data and the view name, allowing a controller to return both in a single object.
View Resolvers are components in Spring MVC that map a logical view name (returned by a controller) to an actual view implementation, such as a physical JSP file or a Thymeleaf template. They decouple the controller from the specific view technology being used in the application.
The main components include the DispatcherServlet (Front Controller), HandlerMapping (URL to Controller mapper), Controller (Request processor), ViewResolver (View mapper), and the View (Template). Together, these components coordinate to handle a web request from entry to the final HTML/JSON response.
Annotations10
The @ComponentScan annotation tells Spring to scan the current package and its sub-packages for classes annotated with @Component, @Service, @Repository, and @Controller. It is the mechanism that allows Spring to automatically discover and register beans without explicit XML or Java configuration.
The @Configuration annotation indicates that a class contains one or more @Bean methods and may be processed by the Spring container to generate bean definitions. It serves as a modern, Java-based alternative to traditional XML configuration files, providing a type-safe way to define beans.
This annotation enables Spring Boot's automatic configuration feature. It directs Spring Boot to 'guess' and configure the beans you are likely to need based on the JAR dependencies you have added to your project, which is a key part of the Spring Boot 'magic' that simplifies setup.
This annotation is used to conditionally load a bean or configuration based on the presence and value of a specific property in the environment (like application.properties). It is widely used in Spring Boot auto-configuration to enable or disable features based on user settings.
This annotation ensures that a configuration or bean is only loaded if a specific class is present on the classpath. This allows Spring Boot to provide optional integration with third-party libraries; the configuration is simply ignored if the library's JAR is not included in the project.
The @Lazy annotation is used to delay the initialization of a bean until it is first requested rather than at startup. This can improve application startup time and is also a common technique used to break circular dependencies between two or more Spring-managed beans.
The @Scope annotation defines the lifecycle and visibility of a bean. It is used to override the default 'Singleton' scope, allowing you to specify other scopes like 'Prototype', 'Request', or 'Session', depending on whether you need a new instance for every injection or request.
@PostConstruct is used on a method that needs to be executed after a bean has been initialized and all dependencies injected. @PreDestroy is used on a method to be executed just before a bean is removed from the container, allowing for custom initialization and cleanup logic.
The @ResponseStatus annotation allows you to specify the HTTP status code and optional reason that should be returned when a method completes or a specific exception is thrown. It is a declarative way to handle error codes without manually wrapping every response in a ResponseEntity.
The @CrossOrigin annotation enables Cross-Origin Resource Sharing (CORS) for a specific controller or method. It allows your REST API to accept requests from different domains, which is essential for modern web development where the frontend and backend are often hosted on different servers.
Spring Bean Scope5
Bean scopes determine the duration of a bean's life and who can see it. While standard Java objects are managed by the developer, Spring beans are managed by the IoC container. Scopes provide a way to control if a bean is a global singleton or a unique instance per request.
Singleton is the default scope in Spring. The container creates only one instance of the bean and shares it everywhere the bean is required. This is efficient for stateless beans, like Services and Repositories, as it minimizes memory overhead and the cost of object creation.
In the Prototype scope, the Spring container creates a brand new instance of the bean every single time it is requested from the container. Use this scope for beans that maintain state for a specific operation or user and should not be shared across threads or requests.
'Request' scope creates a bean instance for a single HTTP request; the instance is discarded once the request is complete. 'Session' scope creates an instance that lives for the duration of an HTTP session, allowing you to store user-specific data that persists across multiple requests.
The default scope for a Spring bean is 'Singleton'. This means that unless explicitly configured otherwise using the @Scope annotation, Spring will only ever create and manage one instance of that class for the entire lifecycle of the application context.
Spring Boot Starters5
This starter includes all the dependencies required for building web applications, including RESTful services. It brings in Spring MVC, Jackson (for JSON), and an embedded Tomcat server, allowing you to start writing web endpoints with just a few lines of configuration.
This starter provides the necessary libraries for using Java Persistence API (JPA) with Hibernate. It simplifies database connectivity by including the Spring Data JPA repositories, Hibernate core, and necessary transaction management, making it much easier to interact with relational databases.
This starter enables Spring Security for your application. By simply adding this dependency, Spring Boot automatically secures all your endpoints with basic authentication and provides a framework for building complex authentication and authorization flows like OAuth2 or JWT.
This is the primary starter for testing Spring Boot applications. It includes a comprehensive suite of libraries such as JUnit 5, AssertJ, Hamcrest, and Mockito, along with Spring Test modules for integration testing and MockMvc for testing web layers.
Spring Boot Actuator provides production-ready features that help you monitor and manage your application. It exposes various HTTP endpoints that provide insights into application health, metrics, environment variables, and log levels, which are essential for DevOps and production support.
Autoconfiguration & Embedded Server9
It works by scanning the classpath for specific JARs and checking for @Conditional annotations in configuration classes. Based on what it finds (e.g., a database driver), it automatically instantiates and configures the necessary beans, following a set of predefined 'recipes' to build the application environment.
The @Conditional annotation is the foundation of Spring's conditional configuration. It allows a bean to be created only if a specific condition is met, such as a property being set, a class being available, or a specific bean already being present in the context.
You can disable specific auto-configuration classes using the 'exclude' attribute of the @SpringBootApplication annotation (e.g., @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})) or by setting the 'spring.autoconfigure.exclude' property in your application.properties file.
An embedded server is a web server that is part of your application's compiled code rather than a separate installation. It allows you to run your application as a simple JAR file without needing to install or manage a separate application server like Tomcat or JBoss.
These are the three servlet containers supported by Spring Boot as embedded servers. Tomcat is the default. Jetty is known for being lightweight and modular. Undertow is a high-performance web server from JBoss that is particularly efficient for high-concurrency and non-blocking I/O.
To change the server, you must exclude the default Tomcat starter from 'spring-boot-starter-web' in your build file (pom.xml or build.gradle) and then explicitly add the starter for the desired server, such as 'spring-boot-starter-jetty' or 'spring-boot-starter-undertow'.
The default port can be changed by setting the 'server.port' property in the application.properties file (e.g., server.port=9090). You can also set this via command-line arguments or environment variables to override the port dynamically at runtime.
To deploy as a WAR, you must change the packaging to 'war' in your build file, make your main class extend 'SpringBootServletInitializer', and override the 'configure' method. This allows the application to be picked up and run by an external, standalone servlet container.
JAR deployment uses an embedded server and is self-contained, making it ideal for microservices and cloud environments. WAR deployment is meant for hosting on a standalone, external application server that manages multiple applications, which is more traditional in legacy enterprise environments.
Actuators9
Actuator is a sub-project of Spring Boot that adds production-ready monitoring and management capabilities. It provides a set of built-in endpoints that allow you to check the status, health, and configuration of your running application without having to write any additional code.
Actuator endpoints are RESTful URLs that expose management information about the application. By default, several are available, such as /health and /info. Others can be enabled to show bean definitions, environment properties, thread dumps, and mapping information for all registered web controllers.
The /health endpoint provides a simple 'UP' or 'DOWN' status of the application. It can be configured to show more detail, such as the status of database connections, disk space, and other downstream services, which is vital for orchestration tools like Kubernetes.
The /info endpoint displays arbitrary application information that you define in your configuration files. It is commonly used to show the application version, build number, and git commit details, providing a way to verify exactly which version of the code is running.
The /metrics endpoint provides a wealth of information about application performance, including memory usage, garbage collection frequency, HTTP request counts, and response times. This data is often integrated with monitoring tools like Prometheus and Grafana for real-time visualization.
You can enable or disable endpoints using properties in application.properties. By default, most are disabled for security. Use 'management.endpoint.<id>.enabled=true' to enable a specific endpoint, or use 'management.endpoints.enabled-by-default=false' to turn off everything and then selectively enable only what you need.
Actuator endpoints often expose sensitive data and should be secured using Spring Security. You can restrict access by configuring request matchers in your SecurityFilterChain to require a specific role (e.g., 'ADMIN') for any path starting with '/actuator/**', ensuring only authorized personnel can view system metrics or health details.
Custom endpoints are created by annotating a class with @Endpoint and defining methods with @ReadOperation (GET), @WriteOperation (POST), or @DeleteOperation (DELETE). Once the class is registered as a Spring bean, Spring Boot automatically exposes it under the '/actuator' path, allowing you to monitor application-specific logic.
In production, Actuator is used for real-time monitoring and alerting. Infrastructure tools like Prometheus scrape the /metrics endpoint, while Kubernetes uses /health as liveness and readiness probes. It allows DevOps teams to perform thread dumps, view environment configurations, and monitor heap usage without restarting the application.
Spring Security16
Spring Security is a powerful and highly customizable authentication and access-control framework for Java applications. It is the de-facto standard for securing Spring-based applications, providing protection against attacks like session fixation, clickjacking, and cross-site request forgery (CSRF) while supporting various authentication protocols like OAuth2 and LDAP.
Authentication is the process of verifying *who* a user is (e.g., via username and password). Authorization is the process of determining *what* an authenticated user is allowed to do (e.g., checking if they have the 'ADMIN' role to delete a user). Authentication always precedes authorization in the security lifecycle.
The @EnableWebSecurity annotation is used to enable Spring Security's web security support in an application. It is typically placed on a configuration class to indicate that the class will define the security filter chain and other security-related beans, allowing for full customization of the web security layer.
Modern Spring Security configuration is done by creating a bean of type SecurityFilterChain. Within this bean, you use an HttpSecurity object to define which URLs are public or protected, specify the login mechanism (formLogin, httpBasic, etc.), and configure logout and CSRF settings in a functional, declarative style.
SecurityFilterChain is an interface that defines a list of Filters that should be applied to a given request. It is the backbone of Spring Security's architecture. When a request arrives, it passes through this chain of filters, which handle tasks like token extraction, session validation, and permission checks.
UserDetailsService is a core interface used to retrieve user-related data. It has a single method, loadUserByUsername, which returns a UserDetails object. Developers implement this interface to fetch user credentials and authorities from a data source, such as a database, for use during the authentication process.
PasswordEncoder is an interface for performing a one-way transformation of a password to let the password be stored securely. Implementations like BCryptPasswordEncoder use strong hashing algorithms with random salts, ensuring that even if the database is compromised, the original plaintext passwords remain unrecoverable.
In-memory authentication is implemented by defining an InMemoryUserDetailsManager bean. You create 'User' objects with hardcoded credentials and roles and provide them to the manager. This approach is simple and ideal for testing or small internal applications where a full database setup is not required.
To implement database authentication, you create a class that implements UserDetailsService and overrides loadUserByUsername. Inside this method, you use a Repository to find the user in your database. You then map your database user entity to Spring's UserDetails object, including their hashed password and roles.
JWT is a compact, URL-safe means of representing claims to be transferred between two parties. It consists of three parts: a header, a payload (containing user info/roles), and a signature. JWTs are used for stateless authentication because all the necessary user data is contained within the token itself.
Implementation involves three steps: 1. A login controller that validates credentials and generates a JWT. 2. A custom filter (extending OncePerRequestFilter) that intercepts every request to extract and validate the JWT. 3. Adding this custom filter to the SecurityFilterChain before the UsernamePasswordAuthenticationFilter.
OAuth2 is an open standard authorization framework that enables third-party applications to obtain limited access to user accounts on an HTTP service (like Google or GitHub). It works by delegating user authentication to the service that hosts the user account and authorizing third-party applications to access the account resources.
OAuth2 is an authorization *framework* (defining how actors interact to grant access), while JWT is a *token format* used to share information. OAuth2 often uses JWTs as access tokens. JWT is stateless and self-contained, whereas a full OAuth2 implementation typically involves a stateful Authorization Server.
Authentication filters are components in the SecurityFilterChain responsible for processing specific types of credentials. For example, UsernamePasswordAuthenticationFilter handles form-based logins, while BasicAuthenticationFilter handles HTTP Basic headers. These filters extract credentials and pass them to an AuthenticationManager for verification.
Cross-Site Request Forgery (CSRF) protection is a security mechanism that prevents unauthorized commands from being transmitted from a user that the web application trusts. Spring Security provides this by generating a unique token for each session, which must be included in any state-changing request (POST, PUT, DELETE).
CORS (Cross-Origin Resource Sharing) is a browser security feature that restricts web pages from making requests to a different domain than the one that served the page. In Spring Boot, you configure it using the @CrossOrigin annotation or by defining a WebMvcConfigurer bean with global CORS mapping rules.
Spring Data & Hibernate30
Spring Data is a high-level Spring project whose purpose 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 easy to use data access technologies, relational and non-relational databases, and cloud-based data services.
Spring Data JPA is a part of the larger Spring Data family that makes it easy to implement JPA-based repositories. It reduces the amount of boilerplate code required to implement data access layers by allowing developers to define repository interfaces and automatically generating the implementation at runtime.
JPA (Java Persistence API) is a specification or a set of guidelines that defines how Java objects are mapped to relational databases. Hibernate is a specific implementation (provider) of the JPA specification. Think of JPA as the interface and Hibernate as the actual engine that performs the work.
ORM is a programming technique used to convert data between incompatible type systems—specifically, between the object-oriented objects in Java and the relational tables in a SQL database. It allows developers to interact with the database using Java code instead of writing complex SQL queries manually.
The @Entity annotation is used to mark a Java class as a JPA entity. It indicates that the class is mapped to a database table. Every entity class must have a no-argument constructor and a primary key defined using the @Id annotation to be valid in the persistence context.
The @Table annotation is used to specify the details of the database table that an @Entity class is mapped to. While optional (JPA defaults to the class name), it is useful for specifying a different table name, schema, or unique constraints that should be applied to the table in the database.
The @Id annotation is used to specify the primary key of an entity. Every JPA entity must have an @Id field. It can be applied to a single field for a simple primary key or to multiple fields for a composite primary key, uniquely identifying each row in the database table.
The @GeneratedValue annotation is used to specify how the primary key value should be generated. Common strategies include 'IDENTITY' (database-side auto-increment), 'SEQUENCE' (using a database sequence), and 'UUID'. It relieves the developer from manually assigning unique IDs to every new object instance.
The @Column annotation is used to customize the mapping between a Java field and a database column. It allows you to specify properties like the column name, length, nullability, and whether the column should be unique or updatable, providing fine-grained control over the database schema generation.
CrudRepository is a generic interface provided by Spring Data for generic CRUD (Create, Read, Update, Delete) operations on a repository for a specific type. it provides built-in methods like save(), findById(), and delete(), eliminating the need to write custom DAO code for basic operations.
JpaRepository is a JPA-specific extension of PagingAndSortingRepository. It includes all the CRUD and pagination features but adds JPA-specific operations, such as flushing the persistence context (saveAndFlush()) and deleting records in batches, making it the most commonly used repository interface in Spring Boot applications.
PagingAndSortingRepository is an extension of CrudRepository that adds additional methods to retrieve entities using pagination and sorting abstraction. It allows you to fetch data in small 'pages' and sort results by multiple properties, which is essential for performance in applications with large datasets.
CrudRepository handles basic CRUD. PagingAndSortingRepository adds pagination/sorting support. JpaRepository extends both and adds JPA-specific methods like flushing. Generally, JpaRepository is preferred for relational databases as it offers the most comprehensive set of features for data manipulation and query management.
Derived query methods allow you to define database queries simply by naming an interface method according to Spring Data's naming conventions. For example, 'findByEmail(String email)' automatically generates a 'SELECT * FROM table WHERE email = ?' query at runtime, greatly reducing the need for manual SQL or JPQL.
The @Query annotation allows you to define a custom query directly on a repository method. It is used when the method naming convention (derived queries) is not sufficient for complex logic. You can write either JPQL (working with Java objects) or Native SQL (working with database tables) inside the annotation.
JPQL (Java Persistence Query Language) operates on entity objects and their properties, making the query database-independent. Native queries are written in the specific SQL dialect of the underlying database. Use JPQL for portability and Native queries for performance-critical tasks or database-specific features not supported by JPA.
A named query is a static query defined using the @NamedQuery annotation on an entity class. These queries are compiled once when the persistence unit is loaded, which can provide a slight performance improvement over dynamic queries and allows for central management of complex queries associated with an entity.
To implement pagination, you pass a Pageable object (created via PageRequest.of(page, size, sort)) to a repository method that returns a Page<T>. Sorting can be included in the Pageable object or passed separately as a Sort object, allowing you to easily handle complex data table requirements.
Pageable is an interface used to encapsulate information about pagination and sorting. It defines properties like the page number, the page size, and the sorting criteria. When passed to a Spring Data repository method, the framework automatically appends the correct LIMIT and OFFSET clauses to the SQL query.
The @Transactional annotation is used to define the scope of a single database transaction. When applied to a method, Spring ensures that all database operations within that method are treated as a single unit of work; if any operation fails, the entire transaction is rolled back to maintain data integrity.
Propagation levels define how transactions relate to each other. 'REQUIRED' (default) uses an existing transaction or creates a new one. 'REQUIRES_NEW' always starts a fresh transaction, suspending any existing one. Others like 'MANDATORY' or 'NEVER' enforce strict rules on whether a transaction must or must not already exist.
Isolation levels define how a transaction is insulated from data changes made by other concurrent transactions. Common levels include 'READ_COMMITTED' (prevents dirty reads) and 'SERIALIZABLE' (highest isolation, prevents all anomalies but slowest). They help manage database consistency and prevent issues like non-repeatable reads or phantom reads.
'save()' is part of CrudRepository; it schedules the entity to be saved, but the actual SQL INSERT/UPDATE may be delayed until the transaction ends. 'saveAndFlush()' is a JpaRepository method that forces Hibernate to push the changes to the database immediately within the current transaction.
'findById()' returns an Optional and performs an immediate database hit. 'getById()' (deprecated in favor of getReferenceById()) returns a lazy proxy object without hitting the database immediately. Use 'findById()' when you need the actual data and 'getById()' when you only need a reference for a relationship mapping.
JPA entities pass through four states: 1. Transient (newly created, not in DB); 2. Persistent (associated with a session and in DB); 3. Detached (session closed, changes not tracked); and 4. Removed (marked for deletion). Understanding these states is crucial for managing object state and database synchronization.
Eager loading fetches the associated data immediately along with the main entity. Lazy loading delays the fetching of associated data until it is actually accessed in code. Lazy loading is generally preferred for performance as it avoids loading unnecessary data until it is absolutely required.
These annotations define relational mappings between entities. @OneToOne maps a single instance to another. @OneToMany maps one instance to a collection. @ManyToOne maps many instances to one. @ManyToMany maps collections to each other, typically requiring a join table. They define the structural relationships within the database schema.
The N+1 problem occurs when JPA executes one query to fetch N parent entities and then N additional queries to fetch the associated child entities. This is highly inefficient. It is typically solved by using 'JOIN FETCH' in JPQL queries or by defining an @EntityGraph to fetch associations in a single query.
The @EntityGraph annotation is a JPA feature that allows you to define a plan for fetching associations and attributes in a single query. It overrides the default fetch type (Lazy/Eager) for a specific repository method, serving as an elegant solution to the N+1 query problem without changing global entity mapping.
The Second Level Cache is a cache that exists outside the JPA Session and is shared across all sessions in an application. It stores entity data to reduce database hits. While the First Level Cache is session-specific and mandatory, the Second Level Cache is optional and requires an external provider like Ehcache or Redis.
Spring Data MongoDB & JDBC5
Spring Data MongoDB is a part of the Spring Data project that provides a familiar, interface-based programming model for interacting with the MongoDB NoSQL database. It allows you to map Java objects to BSON documents and provides repository abstractions similar to JPA for standard CRUD and query operations.
MongoDB is a NoSQL, document-oriented database that stores data in flexible, JSON-like BSON documents rather than fixed tables and rows. It does not require a predefined schema, making it ideal for hierarchical data and rapidly changing requirements, whereas relational databases focus on strict schemas and ACID-compliant joins.
Spring Data JDBC is a conceptual alternative to Spring Data JPA that provides a simpler, more limited approach to data access. It does not support lazy loading, caching, or complex entity state tracking. It focuses on being a lightweight wrapper around JDBC that still offers repository abstractions without the overhead of Hibernate.
Spring Data JPA is built on Hibernate and supports advanced features like lazy loading, dirty checking, and complex mappings. Spring Data JDBC is much simpler and maps directly to the database without a persistence context. JDBC is often preferred for microservices where low memory overhead and predictable SQL execution are critical.
Use JPA for complex enterprise applications with many entity relationships and where automatic state management is beneficial. Use JDBC for simple CRUD services, performance-critical applications, or when you need total control over every SQL query executed without the 'magic' of an ORM persistence context.
Exception Handling & Validation15
Exceptions are typically handled using a combination of @ExceptionHandler methods within controllers or a global approach using @ControllerAdvice. This allows you to catch specific exceptions and return a structured JSON error response with an appropriate HTTP status code, ensuring a consistent API error format.
The @ExceptionHandler annotation is used to define a method that handles specific exceptions thrown by a controller. It can be placed directly inside a @Controller class to handle local errors, or within a @ControllerAdvice class to apply the error-handling logic across all controllers in the application.
@ControllerAdvice is a specialization of @Component that allows you to write code that is applied globally to all controllers. It is most commonly used for global exception handling, but it also supports global @ModelAttribute methods and @InitBinder configurations, promoting a clean separation of error logic from business logic.
@RestControllerAdvice is a convenient combination of @ControllerAdvice and @ResponseBody. It works exactly like @ControllerAdvice but ensures that the return values of the exception handler methods are automatically serialized into the response body (typically JSON), which is the standard for REST APIs.
@ControllerAdvice is designed for standard Spring MVC applications that may return views (HTML). @RestControllerAdvice is specifically for RESTful services where error responses must be data-driven (JSON/XML). The latter eliminates the need to add @ResponseBody to every method inside the advice class.
You define a custom Java class (e.g., ErrorDetails) containing fields like timestamp, message, and details. In your @ExceptionHandler method, you instantiate this class with the error info and return it wrapped in a ResponseEntity, allowing you to specify both the JSON structure and the HTTP status code.
ResponseEntityExceptionHandler is a convenient base class for @ControllerAdvice implementations. It provides default handling for internal Spring MVC exceptions (like method argument not valid or type mismatch), allowing you to override specific methods to provide custom logic while keeping the standard Spring error structure.
Bean Validation is a Java standard (JSR 380) for defining constraints on object properties using annotations. Spring Boot integrates with Hibernate Validator to automatically validate incoming request objects (like DTOs) before they reach the controller logic, ensuring data integrity at the entry point.
@NotNull ensures the value is not null. @NotEmpty ensures it is not null and has a size > 0. @NotBlank ensures it is not null and contains at least one non-whitespace character. Others include @Size for length, @Email for formatting, and @Min/@Max for numeric ranges.
The @Valid annotation is used to trigger validation on a method argument, usually a @RequestBody DTO in a controller. When Spring encounters @Valid, it invokes the Bean Validation provider to check the constraints on the object; if validation fails, it throws a MethodArgumentNotValidException.
@Validated is a Spring-specific annotation that serves two purposes: it enables 'validation groups' (validating different fields in different scenarios) and it allows for method-level validation on Spring beans (like validating @Service method parameters) when placed at the class level.
@Valid is the standard JSR 303 annotation used for basic validation of nested objects and controller payloads. @Validated is a Spring-specific variant that supports validation groups and is required for validating parameters in classes that are not controllers (e.g., Service-level parameter validation).
BindingResult is an object that holds the result of the validation and contains any errors that occurred during the binding process. It must be placed immediately after the model object being validated in the controller method signature, allowing the developer to manually check and handle validation failures.
You create a custom validator by defining a new annotation and a corresponding class that implements the ConstraintValidator interface. You implement the 'isValid' method with your custom logic, allowing you to reuse complex validation rules (like checking a unique username) throughout your application.
Global validation handling is done within a @ControllerAdvice class by overriding the 'handleMethodArgumentNotValid' method of ResponseEntityExceptionHandler. This allows you to collect all validation errors from the exception, format them into a user-friendly list, and return a 400 Bad Request response.
Testing15
Spring Boot provides a comprehensive testing suite that supports unit, slice, and integration testing. It uses @SpringBootTest for full context tests and specialized annotations like @WebMvcTest or @DataJpaTest for testing specific layers in isolation with high performance.
@SpringBootTest is used for full integration testing. It starts the entire Spring ApplicationContext, allowing you to test how all layers of the application work together. While very thorough, it is slower than slice tests and is typically used for end-to-end testing scenarios.
@WebMvcTest is used for 'slice testing' the web layer. It only initializes the Spring MVC infrastructure (controllers, filters, and advice) and does not load services or repositories. You typically use @MockBean to provide mocked versions of dependencies to test controller logic in isolation.
@DataJpaTest is a slice test for the persistence layer. It configures an in-memory database (like H2), scans for @Entity classes, and configures Spring Data JPA repositories. Tests are transactional and roll back by default, ensuring that database tests do not interfere with each other.
@SpringBootTest loads the complete application context and is suited for integration tests. @WebMvcTest focuses only on the web layer, making it much faster and more focused for unit testing controllers. If you use @WebMvcTest, you must manually mock any service-layer dependencies.
@MockBean is a Spring Boot-specific annotation that creates a Mockito mock of a bean and adds it to the ApplicationContext. It replaces any existing bean of the same type in the context, allowing you to easily simulate the behavior of downstream services during integration or slice tests.
@Mock is a standard Mockito annotation used in plain unit tests to create a mock object. @MockBean is used in Spring Boot tests to create a mock and automatically inject it into the Spring ApplicationContext, allowing other beans to interact with the mock during the test.
MockMvc is a powerful class used to test Spring MVC controllers without starting a full HTTP server. It provides a DSL to perform requests (GET, POST, etc.), verify status codes, inspect headers, and assert that the returned JSON or HTML content matches expected values.
REST controllers are best tested using @WebMvcTest along with MockMvc. This combination allows you to simulate HTTP requests and verify that the controller correctly handles inputs, performs validation, calls the service layer (which is mocked), and returns the correct JSON response structure.
TestRestTemplate is a specialized template used for integration testing. Unlike MockMvc, it performs actual HTTP calls against a running server (usually started on a random port). It is ideal for end-to-end tests where you want to verify the entire network stack and serialization process.
@AutoConfigureMockMvc is used in combination with @SpringBootTest to enable MockMvc within a full context integration test. It allows you to use the MockMvc DSL to perform internal requests against the full application context rather than just a web-layer slice.
JPA testing verifies that your repository queries and entity mappings work correctly. By using @DataJpaTest, Spring Boot provides an embedded database and a TestEntityManager. You write standard JUnit methods to save data and then assert that your repository methods return the expected results.
Mock MVC testing is a server-side testing technique that allows you to test the web layer by mocking the DispatcherServlet. It is extremely fast because it bypasses the network layer and does not require an embedded server, yet it still executes all Spring MVC logic including filters and interceptors.
The service layer is usually tested using plain JUnit and Mockito unit tests. You annotate the test class with @ExtendWith(MockitoExtension.class), use @Mock to mock repositories, and @InjectMocks to instantiate the service with those mocks, allowing for fast, isolated logic verification.
Important attributes include 'webEnvironment', which can be set to MOCK (default), RANDOM_PORT, or DEFINED_PORT. Another is 'properties', which allows you to define specific environment properties for the test, overriding application.properties values for that specific test run.
Microservices & Spring Cloud19
Microservices are an architectural style where an application is built as a collection of small, independent services that communicate over a network (usually via REST or messaging). Each service is focused on a specific business capability, has its own database, and can be deployed independently.
Spring Cloud is a collection of tools that provide solutions for common patterns in distributed systems, such as configuration management, service discovery, circuit breakers, and intelligent routing. It builds upon Spring Boot to make developing robust cloud-native applications much simpler.
Service Discovery is the process by which services in a microservice network find each other's network locations (IP and port) dynamically. Instead of hardcoding URLs, services register themselves with a central registry and query it to find the current location of other services.
Eureka is a REST-based service registry developed by Netflix and integrated into Spring Cloud. It acts as the central naming server where all microservices register their instances. Other services can then look up these instances to perform load-balanced requests across the cluster.
To register a service, you add the 'spring-cloud-starter-netflix-eureka-client' dependency and the @EnableDiscoveryClient or @EnableEurekaClient annotation. You then configure the Eureka server's URL in your application properties, and Spring Boot handles the registration heartbeat automatically.
An API Gateway is a single entry point for all client requests in a microservices architecture. It handles cross-cutting concerns like authentication, rate limiting, and request routing, shielding clients from the complexity of the internal microservice network structure.
Spring Cloud Gateway is a library for building an API Gateway on top of Spring WebFlux. It provides a simple way to route requests based on predicates and filters, allowing you to modify requests and responses as they pass through the gateway in a non-blocking, reactive manner.
The Circuit Breaker pattern prevents a cascading failure in a distributed system. If a downstream service is failing, the circuit breaker 'trips' and immediately returns an error or a fallback response instead of waiting for a timeout, giving the failing service time to recover.
Resilience4j is a lightweight fault-tolerance library designed for Java 8 and functional programming. It is the modern replacement for Hystrix in the Spring Cloud ecosystem, providing components for circuit breaking, rate limiting, retrying, and bulkheading with a very low memory footprint.
Hystrix was Netflix's original circuit breaker library. It provided latency and fault tolerance by isolating points of access between remote systems. While it is now in maintenance mode, it pioneered many of the patterns used in modern tools like Resilience4j.
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. It allows you to have a central place (like a Git repository) to manage configuration properties for all applications across all environments, with support for real-time updates.
The Config Server is a standalone Spring Boot application that acts as a central repository for configurations. It exposes an API that clients use to retrieve their properties. It supports various backends, including Git, SVN, Vault, and the local file system.
Feign is a declarative web service client. It makes writing web service clients easier by allowing you to define an interface and annotate it. Spring Cloud OpenFeign provides auto-configuration for Feign, enabling you to call other microservices as if they were local Java methods.
Spring Cloud OpenFeign is the Spring-integrated version of Feign. It supports Spring MVC annotations (like @GetMapping) on interfaces and automatically integrates with Eureka for service discovery and Spring Cloud LoadBalancer for client-side load balancing, making inter-service communication seamless.
Load balancing is the process of distributing incoming network traffic across multiple servers. In microservices, this ensures that no single instance is overwhelmed, improving availability and responsiveness. Go supports both server-side load balancing (via Gateway) and client-side load balancing (via LoadBalancer library).
Ribbon was Netflix's client-side load balancer which is now in maintenance mode. Spring Cloud LoadBalancer is the modern, non-blocking alternative provided by the Spring team. Unlike Ribbon, it doesn't require a separate thread pool and is built on top of Project Reactor, making it much more resource-efficient.
Distributed tracing is a method used to profile and monitor applications, especially those built using microservices. It tracks the path of a request as it travels through various services, assigning a unique Trace ID to the entire journey and Span IDs to individual service calls, allowing for easy bottleneck identification.
Spring Cloud Sleuth is a library that provides distributed tracing by adding trace and span IDs to logs and HTTP headers. Zipkin is a visualization tool that collects these timing data. Together, they allow developers to see a graphical representation of how long requests take across a distributed system.
A service mesh is a dedicated infrastructure layer for handling service-to-service communication. Unlike Spring Cloud, which handles these concerns via libraries inside the application (like Feign or Resilience4j), a service mesh like Istio uses 'sidecar' proxies to handle security, traffic management, and observability externally.
Microservices & Microservices & Spring Cloud1
You implement it by setting up a Config Server that points to a configuration source (like Git). Microservices then act as Config Clients; upon startup, they connect to the Config Server to fetch their environment-specific properties before the local application context is even initialized.
Advanced Topics15
Caching is the process of storing the results of expensive operations (like database queries or API calls) in memory so that subsequent requests can be served faster. Spring Boot provides a cache abstraction that allows you to enable caching with a few annotations without coupling your code to a specific provider.
@Cacheable triggers cache population (skip method if found in cache). @CachePut updates the cache without interfering with the method execution. @CacheEvict removes entries from the cache. These annotations provide a declarative way to manage the lifecycle of cached data based on method parameters and results.
Spring Boot supports various providers through its CacheManager interface. Common ones include Caffeine (high-performance local cache), Ehcache (feature-rich), Redis (distributed cache), and Hazelcast (in-memory data grid). If no specific provider is found, Spring defaults to a simple ConcurrentHashMap-based provider.
Spring Batch is a robust framework designed for the development of batch applications. It handles high-volume, repetitive processing of data (like end-of-day reports or data migration) with features like transaction management, job processing statistics, restartability, and skip/retry logic for fault tolerance.
Scheduling allows you to execute tasks at specific intervals or times. By using the @EnableScheduling and @Scheduled annotations, you can run background tasks automatically, such as sending daily emails, cleaning up old database records, or synchronizing data with external systems using Cron expressions.
The @Scheduled annotation marks a method to be executed on a schedule. It supports 'fixedRate' (run every X ms), 'fixedDelay' (run X ms after the last execution finishes), and 'cron' (using standard linux-style cron expressions), providing total control over task timing and frequency.
Async processing allows a method to run in a separate background thread, releasing the main thread immediately. This is useful for long-running tasks like sending emails or generating reports that shouldn't block the HTTP response. It is enabled using @EnableAsync and implemented with the @Async annotation.
The @Async annotation tells Spring to execute the method in a separate thread pool. For the caller, the method returns immediately, often with a Future or CompletableFuture object. This allows the application to achieve higher throughput by offloading non-critical tasks to worker threads.
The @EnableAsync annotation is a configuration-level annotation that enables Spring's ability to detect and process @Async annotations. Without this, @Async methods will simply run synchronously in the same thread as the caller, ignoring the asynchronous request entirely.
File upload is handled by defining a controller method that accepts a 'MultipartFile' parameter. You then use the transferTo() method to save the file to a permanent directory on the server, ensuring that the 'spring.servlet.multipart' properties are configured for maximum file size limits.
File download is implemented by returning a 'Resource' (like FileSystemResource) or a byte array in a ResponseEntity. You must set the 'Content-Disposition' header to 'attachment' and provide a filename so that the browser knows to download the file rather than display it.
MultipartFile is a Spring-specific interface that represents an uploaded file received in a multipart request. It provides methods to get the original filename, file size, content type, and an input stream to read the file data, simplifying the handling of binary data in web controllers.
CORS configuration defines which origins (domains), headers, and methods are allowed to access your REST API from a web browser. In Spring Boot, this can be done globally via a WebMvcConfigurer bean or locally using the @CrossOrigin annotation on specific controller methods.
i18n is implemented by creating 'messages.properties' files for different locales (e.g., messages_en.properties). You then use a MessageSource bean to retrieve locale-specific strings. Spring Boot automatically detects the user's locale based on the 'Accept-Language' HTTP header or a custom LocaleResolver.
MessageSource is a Spring interface used for resolving text messages, supporting parameterization and internationalization. It allows you to externalize all UI strings into properties files, making the application easy to translate into different languages without changing the source code.
TOP 30 CRITICAL6
To connect to a database, you add the relevant JDBC driver and 'spring-boot-starter-data-jpa' to your build file. You then provide the connection details (URL, username, password) in application.properties. Spring Boot's auto-configuration automatically creates a HikariCP DataSource bean and wires it into the context.
Spring Boot applications are typically deployed as executable 'fat' JARs that contain all dependencies and an embedded server. You simply run 'java -jar app.jar' on any machine with a JVM. Alternatively, they can be containerized using Docker or deployed as WARs to external application servers.
In modern Spring Data, findById() returns an Optional<T>, forcing the developer to handle the case where the record doesn't exist. findOne() was used in older versions and returned null if not found. This change promotes better null-safety and follows modern Java 8+ patterns.
@Primary is used when you have multiple beans of the same type and want to specify a 'default' bean to be injected. If an injection point doesn't use @Qualifier, Spring will automatically pick the @Primary bean, preventing an NoUniqueBeanDefinitionException during startup.
You can exclude specific auto-configuration classes using the 'exclude' attribute of @SpringBootApplication or @EnableAutoConfiguration. Alternatively, you can use the 'spring.autoconfigure.exclude' property in application.properties to prevent certain 'magic' beans from being created at runtime.
Constructor injection is preferred because it allows for final (immutable) dependencies, prevents NullPointerExceptions by ensuring required beans are present at creation, and makes unit testing easier as you can pass mocks through the constructor without needing a Spring container or reflection.