Interview Preparation J2EE & Spring, Spring Boot - Yash-777/MyWorld GitHub Wiki

URL, HTTP Request Response wiki

Uniform Resource Locators (URLs) The Hypertext Transfer Protocol (HTTP) is designed to enable
communications between clients and servers

A URL (Uniform Resource Locator) is the address of a unique resource on the internet. It is one of the key mechanisms used by browsers to retrieve published resources, such as HTML pages, CSS documents, images, and so on.

image
image

The Web Storage API extends the Window object with two new properties β€” Window.sessionStorage and Window.localStorage. β€” invoking one of these will create an instance of the Storage object, through which data items can be set, retrieved, and removed. A different Storage object is used for the sessionStorage and localStorage for each origin (domain).

Document.cookie The Document property cookie lets you read and write cookies associated with the document. It serves as a getter and setter for the actual values of the cookies.

localStorage.setItem('colorSetting', '#a4509b');
document.cookie = "yummy_cookie=choco";

The HTTP/1.0 specification defined the GET, HEAD and POST methods and the HTTP/1.1 specification added five new methods: OPTIONS, PUT, DELETE, TRACE and CONNECT.
HTTP response status codes indicate whether a specific HTTP request has been successfully completed. Responses are grouped in five classes:

πŸ‘‰ Example

@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public ResponseEntity getUser(@PathVariable Long id) {
return Optional
.ofNullable( userRepository.findOne(id) )
.map( user -> ResponseEntity.ok().body(user) )          //200 OK
.orElseGet( () -> ResponseEntity.notFound().build() );  //404 Not found
}

HTTP Request & Response (Object Marshalling, unmarshalling)? In HTTP communication, marshalling converts Java objects to JSON/XML for requests, and unmarshalling converts responses back to Java objects.

Is marshalling the same as serialization? Serialization is Java-specific; marshalling is broader and used in HTTP, REST, and RPC.

Servlet API servlet-api.jar

Servlet lifecycle methods (init, service, destroy, getservletconfig, getservlet)

public abstract interface Servlet {
  public abstract void init(ServletConfig paramServletConfig) throws ServletException;
  public abstract ServletConfig getServletConfig();
  public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
    throws ServletException, IOException;
  public abstract String getServletInfo();
  public abstract void destroy();
}

By default, a web server (or servlet container) creates only one instance of a servlet. When multiple requests arrive for that servlet, each request is processed by a separate thread.
These threads are managed by a thread pool provided by the servlet container (for example, Tomcat).

Call we call destroy() inside service() Β« What will happen? Yes, we can call destroy() from the service() Β« It will execute the code inside destroy() method, but it will not dispose the servlet object. Servlet get instantiated, disposed by the container.

The servlet container creates a ServletRequest & ServletResponse objects and passes both as an arguments to the servlet's service method.

  • To send binary data in a MIME body response, use the ServletOutputStream returned by getOutputStream.
  • To send character data, use the PrintWriter object returned by getWriter.

Spring Framework & Spring Boot

DispatcherServlet is a Spring Framework component, not part of the standard Servlet API. It acts as the front controller in a Spring web application, meaning all incoming HTTP requests first go to the DispatcherServlet.

Using the Servlet API, the DispatcherServlet receives requests from the web container (like Tomcat) and then applies Spring’s web features to process them. It is responsible for:

  • Mapping URLs to controller methods
  • Invoking the correct handler (@Controller, @RestController)
  • Performing data binding and validation
  • Handling exceptions centrally
  • Resolving views and generating responses

Spring Framework: A massive, powerful toolbox (framework) used to build Java applications. It provides features like Dependency Injection (DI) and Inversion of Control (IoC), but it requires you to set everything up manually.

Spring Boot: An extension of Spring that makes it easy to create "stand-alone, production-grade" applications. It takes away the headache of manual configuration. (simplifying configuration is one of the key goals)
Spring Boot Starter Parent Parent pom providing dependency and plugin management for applications built with Maven.

Spring Framework (Control) Spring Boot (Speed)
πŸ‘‰ Core framework for building Java applications πŸ‘‰ Built on top of Spring
Requires manual configuration Auto-configuration
Needs XML / Java config Minimal configuration
No embedded server Embedded server (Tomcat/Jetty)
More boilerplate code Very less
Production-ready features (Actuator)
Full control, but slower setup Faster development

Spring Boot simplifies Spring by providing auto-configuration, embedded servers, and faster application setup.


Spring Framework

Bean: All the objects created by spring container and stores/manages by IOC is called Spring Bean

What is IoC (Inversion of Control)?

Inversion of Control is a design principle where the control of object creation and dependency management is shifted from the program to a container/framework.

πŸ‘‰ Instead of creating objects manually, Spring handles object creation and lifecycle. We only provide configuration information to Spring about how an object should be created and managed.

  • If a bean has dependencies, Spring ensures those dependencies are created and injected first using @Autowired.
  • If the dependency is marked as @Lazy, Spring injects a proxy and creates the actual object only when it is first used.
What are different types of containers in Spring? BeanFactory, ApplicationContext (@Autowired vs @Lazy)

What is the IoC Container?

The IoC container is the core of the Spring Framework. The Spring IoC container is responsible for creating, configuring, and managing the lifecycle of application objects, while injecting their dependencies to promote loose coupling. It is responsible for:

  • Read configuration (XML / annotations / Java config)
  • Create beans
  • Resolve dependencies
  • Inject dependencies
  • Manage lifecycle
Without IoC (tight coupling) With IoC (loose coupling)
class Car {
    Engine engine = new Engine(); // tightly coupled
}
      
class Car {
    Engine engine;
    @Autowored // IOC Creates and Inject dependencies
    Car(Engine engine) {
        this.engine = engine;
    }
}
      

There are basically two types of IOC Containers in Spring:

  1. BeanFactory Container: BeanFactory is like a factory class that contains a collection of beans. It instantiates the bean whenever asked for by clients.
  2. ApplicationContext Container: The ApplicationContext interface is built on top of the BeanFactory interface.

@Autowired and @Lazy are features of the ApplicationContext, not plain BeanFactory.

  • BeanFactory is the basic IoC container
  • ApplicationContext is a more advanced container built on top of BeanFactory
  • Annotation-based dependency injection (like @Autowired, @Lazy, @Component, etc.) is fully supported by ApplicationContext

@Autowired and @Lazy are not features of the core BeanFactory. They are supported by the ApplicationContext, which extends BeanFactory and provides annotation processing via BeanPostProcessors.

Eagerly injected using @Autowired Lazily initialized using @Autowired @Lazy, where Spring injects a proxy and creates the actual bean only when it is accessed
    How @Autowired works (internally)
  • Handled by: AutowiredAnnotationBeanPostProcessor
  • Runs after bean creation
  • Injects dependencies automatically This post-processor is auto-registered by ApplicationContext, not by BeanFactory.
Required dependencies are created first and injected automatically using @Autowired
class Car {
    Engine engine = new Engine(); // tightly coupled
}
      
    How @Lazy works
  • Tells the container when to initialize the bean
  • With ApplicationContext:
    1. Default = eager initialization
    2. @Lazy = initialize only when requested
    Again, processed by the ApplicationContext infrastructure.
    If @Lazy is used along with @Autowired, the dependency is not created immediately
  • A proxy object is injected instead
  • The actual dependency is created and injected only when it is first needed
class Car {
    Engine engine;
    @Autowored // IOC Creates and Inject dependencies
    Car(Engine engine) {
        this.engine = engine;
    }
}
      
@Component
class A {
  @Autowired
  B b;   // created before A
}

@Component
class C {
  @Autowired @Lazy
  A a;   // proxy injected, real A created when used
}
What are the bean scopes in Spring? singleton, prototype, request, session, global-session

There are five types of spring bean scopes:

  • singleton - only one instance of the spring bean will be created for the spring container. This is the default spring bean scope. While using this scope, make sure bean doesn’t have shared instance variables otherwise it might lead to data inconsistency issues.
  • prototype – A new instance will be created every time the bean is requested from the spring container.
  • request – This is same as prototype scope, however it’s meant to be used for web applications. A new instance of the bean will be created for each HTTP request.
  • session – A new bean will be created for each HTTP session by the container.
  • global-session – This is used to create global session beans for Portlet applications.

Spring IoC bean scopes (object creation):

  • Singleton: Only one bean instance per Spring container. bean.getBean() called by T1 and T2 returns the same object.
  • Prototype: A new bean instance is created for each request. bean.getBean() called by T1 and T2 returns different objects.

Common IoC Annotations

Annotation Purpose
@Component Marks a class as a Spring bean
@Service Business logic layer
@Repository Data access layer
@Controller / @RestController Web layer
@Autowired Inject dependencies
@Configuration Configuration class
@Bean Defines a bean

🌱 Spring Bean Lifecycle Spring beans are instantiated and managed by the Spring IoC container. Beans are created by providing bean configuration metadata to the container. This configuration metadata can be provided using XML, annotations, or Java-based configuration.

Create β†’ Inject β†’ Aware β†’ Before β†’ Init β†’ After β†’ Use β†’ Destroy
Spring Bean Lifecycle πŸ”Ή Bean Creation & Initialization Phase πŸ‘‡ diagram-style explanation

1. Read Configuration Metadata: IoC container identifies the bean definition from XML, Java config, or annotations.

2. Bean Instantiation: The bean object is created using reflection.

3. Dependency Injection: Properties are populated via @Autowired, @Value, setter injection, or constructor injection.

4. Aware Interfaces Callbacks (if implemented):

  • setBeanName() β†’ BeanNameAware
  • setBeanClassLoader() β†’ BeanClassLoaderAware
  • setBeanFactory() β†’ BeanFactoryAware

5. ApplicationContext-Specific Aware Callbacks:

  • setResourceLoader() β†’ ResourceLoaderAware
  • setApplicationEventPublisher() β†’ ApplicationEventPublisherAware
  • setMessageSource() β†’ MessageSourceAware
  • setApplicationContext() β†’ ApplicationContextAware
  • setServletContext() β†’ ServletContextAware (web apps only)

6. BeanPostProcessor – Before Initialization: postProcessBeforeInitialization()

7. Initialization Callbacks: @PostConstruct, afterPropertiesSet() β†’ InitializingBean, and custom init-method if defined.

8. BeanPostProcessor – After Initialization: postProcessAfterInitialization()

9. Bean is Ready to Use: ApplicationContext is fully initialized, and the bean is ready for use.

πŸ”Ή Bean Destruction Phase (Container Shutdown):

Executed only for singleton beans:

  • @PreDestroy
  • destroy() β†’ DisposableBean
  • Custom destroy-method (if defined)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 1. Read Bean Configuration  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 2. Bean Instantiation       β”‚
β”‚   (new / reflection)        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 3. Dependency Injection     β”‚
β”‚   (@Autowired, @Value)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 4. Aware Interfaces         β”‚
β”‚   BeanNameAware             β”‚
β”‚   BeanFactoryAware          β”‚
β”‚   ApplicationContextAware   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 5. BeanPostProcessor        β”‚
β”‚   beforeInitialization()    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 6. Initialization           β”‚
β”‚   @PostConstruct            β”‚
β”‚   afterPropertiesSet()      β”‚
β”‚   custom init-method        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7. BeanPostProcessor        β”‚
β”‚   afterInitialization()     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 8. Bean Ready to Use        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               ↓
        (Container Shutdown)
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 9. Destruction Phase        β”‚
β”‚   @PreDestroy               β”‚
β”‚   DisposableBean.destroy()  β”‚
β”‚   custom destroy-method     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
Single Java class that demonstrates all 8 stages of the Spring Bean Lifecycle
package com.example.lifecycle;

import jakarta.annotation.*;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.*;
import org.springframework.stereotype.Component;

@lombok.extern.slf4j.Slf4j @Component
public class BeanLifecycleDemo implements 
        BeanNameAware, BeanFactoryAware, ApplicationContextAware, 
        InitializingBean, DisposableBean, SmartInitializingSingleton {

   {
      // Why Not Use Instance Block?
      // This runs immediately after constructor call, BEFORE dependencies are injected.
   }

    public BeanLifecycleDemo() {
        log.info("1️⃣ Constructor called β€” Bean instance created");
    }
    @Override
    public void setBeanName(String name) {
        log.info("2️⃣ BeanNameAware β€” Bean name set: {}", name);
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("3️⃣ BeanFactoryAware β€” BeanFactory injected");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("4️⃣ ApplicationContextAware β€” ApplicationContext injected");
    }
    @PostConstruct
    public void postConstruct() {
        log.info("5️⃣ @PostConstruct β€” Bean fully constructed and dependencies injected");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("6️⃣ InitializingBean β€” afterPropertiesSet() called");
    }
    @Override
    public void afterSingletonsInstantiated() {
        log.info("7️⃣ SmartInitializingSingleton β€” All singleton beans are now instantiated");
    }

    @PreDestroy
    public void preDestroy() {
        log.info("8️⃣ @PreDestroy β€” Pre-destroy method called before bean is destroyed");
    }
    @Override
    public void destroy() throws Exception {
        log.info("8️⃣ DisposableBean β€” destroy() method called during shutdown");
    }
}

What is Spring Boot Starter Parent?

In a typical Spring Boot project, spring-boot-starter-parent is used as the parent POM. It provides sensible defaults for dependency versions, plugin management, and build configuration, allowing you to avoid repetitive manual setup.

Using a parent POM enables centralized management across one or more child projects, including:

  • Configuration – Java version and other project-wide properties
  • Dependency Management – Consistent, centralized versions for dependencies
  • Default Plugin Configuration – Preconfigured settings for commonly used Maven plugins

This helps ensure consistency, reduces boilerplate, and minimizes version conflicts across projects.

<properties>
    <java.version>17</java.version>
    <resource.delimiter>@</resource.delimiter>
    <maven.compiler.release>${java.version}</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.run.main-class>${start-class}</spring-boot.run.main-class>
</properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
    <archive>
        <manifest>
            <mainClass>${start-class}</mainClass>
            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
        </manifest>
    </archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
    <archive>
        <manifest>
            <mainClass>${start-class}</mainClass>
            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
        </manifest>
    </archive>
</configuration>
</plugin>

What’s happening here?

  • No Java version specified β†’ inherited
  • No dependency versions β†’ managed by Spring Boot
    Spring Boot ensures tested, compatible versions. [Spring Framework, Jackson, Tomcat, Hibernate, Logging (Logback, SLF4J)]
  • No plugin config β†’ auto-configured [maven-compiler-plugin, maven-failsafe-plugin, maven-jar-plugin, maven-war-plugin]
    So this works without extra setup: [mvn spring-boot:run, mvn package]

That’s the magic ✨

What is the purpose of Spring Boot DevTools, and how does it help developers?

Spring Boot DevTools improves developer productivity by enabling automatic application restart and live reload. With DevTools, changes in code or resources are reflected immediately without manually restarting the server.

Maven Dependency:

<!-- Boot LOG:
OptionalLiveReloadServer       : LiveReload server is running on port 35729
LocalDevToolsAutoConfiguration$RestartingClassPathChangeChangedEventListener - Restarting due to 1 class path change (0 additions, 0 deletions, 1 modification)
 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<scope>runtime</scope>
	<optional>true</optional>
</dependency>
@Configuration(proxyBeanMethods = false)
@ConditionalOnInitializedRestarter
@EnableConfigurationProperties(DevToolsProperties.class)
public class LocalDevToolsAutoConfiguration {
   // Local LiveReload configuration.
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnProperty(prefix = "spring.devtools.livereload", name = "enabled", matchIfMissing = true)
   static class LiveReloadConfiguration {

   }

   // Local Restart Configuration.
   @Lazy(false)
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnProperty(prefix = "spring.devtools.restart", name = "enabled", matchIfMissing = true)
   static class RestartConfiguration {

   }
}

DevTools watches for changes β†’ restarts the IoC container β†’ all beans (auto-configured or custom) are reloaded without manual server restart.

Adding the spring-boot-devtools dependency enables automatic restart of the embedded Tomcat on classpath changes, during which Spring Boot auto-configuration re-runs and the IoC container recreates all beans.

Adding the spring-boot-devtools dependency does not allow you to exclude auto-configuration defined in the main method. DevTools only restarts the application context; it does not change or bypass @SpringBootApplication or @EnableAutoConfiguration behavior.

DevTools restarts recreate the ApplicationContext, so auto-configuration always executes again.

[ Code / Classpath Change ]
            β”‚
            β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ Spring Boot DevTools     β”‚
 β”‚ - Detects change         β”‚
 β”‚ - Triggers restart       β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ JVM Restart (partial)    β”‚
 β”‚ - ApplicationContext     β”‚
 β”‚   is closed              β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ @SpringBootApplication   β”‚
 β”‚ (includes                β”‚
 β”‚  @EnableAutoConfiguration)β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ Auto-Configuration Runs  β”‚
 β”‚ - Conditions re-evaluatedβ”‚
 β”‚ - Beans re-created       β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ IoC Container Ready      β”‚
 β”‚ - Embedded Tomcat starts β”‚
 β”‚ - Beans available        β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Key Explanation (Short & Clear)

  • DevTools does not keep the same ApplicationContext
  • It closes and recreates the context on every restart
  • Since @SpringBootApplication includes @EnableAutoConfiguration, auto-configuration always runs again
  • All conditional checks (@ConditionalOnClass, @ConditionalOnBean, etc.) are re-evaluated

@SpringBootApplication annotation serves as the entry point for an application : This is a convenience annotation that is equivalent to declaring @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan. It enables auto-configuration, component scanning, and Java-based configuration in a single annotation.

Annotation Simple Definition What it actually does
@SpringBootConfiguration
Java-based configuration - An alternative to Spring’s standard @Configuration used to declares one or more @Bean methods
The "Blueprint" - A configuration class for defining beans. Tells Spring: "This class contains definitions for beans (objects) that our application needs to run."
@EnableAutoConfiguration
Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added.
The "Mind Reader" - A trigger for auto-configuration based on project dependencies. Tells Spring Boot to look at your pom.xml or classpath & properties and automatically set up things like databases or web servers based on the libraries it finds.
@ComponentScan
to automatically pick up all Spring components, including @Configuration classes.
The "Search Party" - The starting point for component scanning. Tells Spring to look through your packages to find your Controllers, Services, and Components so it can manage them.

Spring Boot’s auto-configuration mechanism inspects the classpath and automatically configures required beans based on available dependencies. For example:

  • If spring-boot-starter-web is present, Spring Boot sets up DispatcherServlet, Tomcat, and other web-related configurations automatically.
  • If spring-boot-starter-data-jpa is included, it configures an EntityManagerFactory, DataSource, and TransactionManager. This eliminates most of the boilerplate and lets developers focus on business logic rather than infrastructure setup.
Source Code of Spring Boot - @SpringBootApplication Annotation
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME)
@Documented @Inherited

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	// Exclude specific auto-configuration classes/names such that they will never be applied.
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	/**
	 * Base packages to scan for annotated components.
	 * Note: this setting is an alias for @ComponentScan only. It has no effect on @Entityscanning or Spring Data Repository scanning.
	 * For those you should add @EntityScan and @Enable...Repositories annotations.
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	// The BeanNameGenerator class to be used for naming detected components within the Spring container.
	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	/**
	 * Specify whether @Bean methods should get proxied in order to enforce
	 * bean lifecycle behavior, e.g. to return shared singleton bean instances even in
	 * case of direct {@code @Bean} method calls in user code. This feature requires
	 * method interception, implemented through a runtime-generated CGLIB subclass which
	 * comes with limitations such as the configuration class and its methods not being
	 * allowed to declare {@code final}.
	 */
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}
A Simple Spring Boot Application : SpringApplication.run(MyApplication.class, args);
Jar Deployment War Deployment
@SpringBootApplication
@ComponentScan(basePackages = "com.github.yash777.myworld") // Scans configuration classes of child modules
@ConditionalOnProperty(
    value = "server.app.war.deployment", 
    havingValue = "NO", 
    matchIfMissing = false
)
public class MyApplication {
/**
 * Standard Spring Boot entry point for launching the application with an embedded web server.
 *
 * @param args Command-line arguments passed to the application.
 */
public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
    
    String[] beanNames = ctx.getBeanDefinitionNames();
    Arrays.sort(beanNames);
    for (String beanName : beanNames) {
        System.out.println(beanName);
    }
}

}
@SpringBootApplication
@ComponentScan(basePackages = "com.github.yash777.myworld")
@ConditionalOnProperty(
value = "server.app.war.deployment",
havingValue = "YES",
matchIfMissing = false
)
public class MyApplicationWarDeployment extends SpringBootServletInitializer implements CommandLineRunner {
public static void main(String[] args) {
    SpringApplication app = new SpringApplication(MyApplicationWarDeployment.class);
    Properties props = new Properties();
    
    // Optional: Define any default properties here if needed.
    app.setBannerMode(Mode.CONSOLE); // Show banner in the console
    app.setDefaultProperties(props);
    
    app.run(args);
}

/**
 * This method is executed after the Spring application context is initialized.
 * Use it to perform any post-startup logic or initialization.
 */
@Override
public void run(String... args) throws Exception {
    // Post-startup logic can go here.
}

}

What is @EnableAutoConfiguration?

At any point, you can start to define your own configuration to replace specific parts of the auto-configuration. Respects user configuration: If you define a bean, Spring Boot backs off.
πŸ‘‰ It tells Spring Boot to automatically configure beans based on:
  • Dependencies in classpath
  • Properties in application.yml / properties
  • Environment (web, JPA, security, etc.)
@Bean
DataSource myDataSource() { ... }
πŸ‘‰ Boot will not create its default DataSource.

If you need to find out what auto-configuration is currently being applied, and why, start your application with the --debug switch. Doing so enables debug logs for a selection of core loggers and logs a conditions report to the console.

@EnableAutoConfiguration loads auto-config classes from metadata : DataSourceAutoConfiguration.class

@EnableAutoConfiguration loads auto-config classes from metadata

Depending on Spring Boot version:

  • Spring Boot ≀ 2.x β†’ META-INF/spring.factories
  • Spring Boot β‰₯ 3.x β†’ META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

πŸ“Œ DataSourceAutoConfiguration is listed in this file : spring-boot-autoconfigure-2.7.18.jar

META-INF/spring.factories β†’ That is what @EnableAutoConfiguration reads.

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\

META-INF/spring-autoconfigure-metadata.properties

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration=
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.AutoConfigureBefore=org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.ConditionalOnClass=javax.sql.DataSource,org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Dbcp2=
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Dbcp2.ConditionalOnClass=org.apache.commons.dbcp2.BasicDataSource
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari=
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari.ConditionalOnClass=com.zaxxer.hikari.HikariDataSource
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$OracleUcp=
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$OracleUcp.ConditionalOnClass=oracle.jdbc.OracleConnection,oracle.ucp.jdbc.PoolDataSourceImpl
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat=
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Tomcat.ConditionalOnClass=org.apache.tomcat.jdbc.pool.DataSource
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@AutoConfigureBefore(SqlInitializationAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
		DataSourceInitializationConfiguration.InitializationSpecificCredentialsDataSourceInitializationConfiguration.class,
		DataSourceInitializationConfiguration.SharedCredentialsDataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
	
}

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {

	private ClassLoader classLoader;

	// Datasource name to use if "generate-unique-name" is false. Defaults to "testdb" when using an embedded database, otherwise null.
	private String name;

	// Fully qualified name of the connection pool implementation to use. By default, it is auto-detected from the classpath.
	private Class<? extends DataSource> type;
	private String driverClassName;
	private String url;
	private String username;
	private String password;
}

Disabling Specific Auto-configuration Classes: If you find that specific auto-configuration classes that you do not want are being applied, you can use the exclude attribute of @SpringBootApplication to disable them, as shown in the following example:

// 1. Exclude in @SpringBootApplication (main class)
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })

// 2. Exclude using @EnableAutoConfiguration
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)

// 3. Exclude via application.properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

If the class is not on the classpath, you can use the excludeName attribute of the annotation and specify the fully qualified name instead. If you prefer to use @EnableAutoConfiguration rather than @SpringBootApplication, exclude and excludeName are also available. Finally, you can also control the list of auto-configuration classes to exclude by using the spring.autoconfigure.exclude property.


Both JAX-RS and Spring REST support path and query parameters; JAX-RS uses @PathParam and @QueryParam, while Spring uses @PathVariable and @RequestParam, with similar URL semantics but different frameworks.

JAX-RS (Jersey) β†’ Java EE / Jakarta EE standard Spring REST β†’ Spring Framework
package javax.ws.rs.*;
@GET
@Path("/orders/{id}")
public String getOrder(
        @PathParam("id") String id,
        @QueryParam("queryParamName") int i) {
    return "Order ID: " + id;
}
      
package org.springframework.web.bind.annotation.*;
@GetMapping("/orders/{id}")
public String getOrder(
        @PathVariable String id,
        @RequestParam("queryParamName") int i) {
    return "Order ID: " + id;
}
      

Bean Ambiguity @Primary
Applied on a bean definition (default bean)
@Qualifier
Applied at the injection point (explicit bean selection)
When multiple beans of the same type exist and Spring tries to inject by type, it cannot decide which one to choose.
@Component
class PaypalService implements PaymentService {}
@Component
class StripeService implements PaymentService {}
@Autowired
private PaymentService paymentService;
// ❌ NoUniqueBeanDefinitionException: expected single matching bean but found 2
Marks one bean as the default choice when multiple beans of the same type exist.
@Component
@Primary
class PaypalService implements PaymentService {}
@Component
class StripeService implements PaymentService {}
@Autowired
private PaymentService paymentService; // PaypalService injected
βœ” Used when one implementation is preferred most of the time.
Explicitly tells Spring which bean to inject by name or qualifier value.
@Component("paypal")
class PaypalService implements PaymentService {}
@Component("stripe")
class StripeService implements PaymentService {}
@Autowired
@Qualifier("stripe")
private PaymentService paymentService; // StripeService injected
βœ” Used when you need precise control over which bean is injected.

When should we choose @Primary instead of @Qualifier in Spring applications?

Use @Primary when one implementation should act as the default most of the time. Use @Qualifier when you need explicit control over which bean is injected. In development, @Qualifier is preferred for clarity, while @Primary is convenient for rare or default cases.

  • @Primary = β€œdefault choice when no qualifier is specified”
Default implementation (used when no property or mysql) The non-primary bean can still be used explicitly with `@Qualifier`.
βœ” If db.to.use is missing or set to mysql β†’ DataRepository = MySqlRepository
@Component
@Primary
@ConditionalOnProperty(
    name = "db.to.use",
    havingValue = "mysql",
    matchIfMissing = true
)
class MySqlRepository implements DataRepository {
}
      
βœ” If db.to.use=graphdb β†’ DataRepository = GraphDbRepository
@Component
@ConditionalOnProperty(name = "db.to.use", havingValue = "graphdb")
class GraphDbRepository implements DataRepository {
}
      
If the property is not specified, Spring falls back to the default implementation, similar to a Maven profile with a default activation.

What are the differences between @Component, @Controller, @RestController, @Service, and @Repository in Spring, and how do they behave in different layers of an application?

Spring Stereotype Annotations

package org.springframework.stereotype;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
   String value() default "";
}

Domain-Driven Design: Below annotation's serves as a specialization of @Component

Controller / RestController (Web Layer) Service (Business Layer) Repository (Data Access Layer)
@Component
public @interface Controller {
   @AliasFor(annotation = Component.class)
   String value() default "";
}
      
- RestController combines @Controller + @ResponseBody automatically.
- @RestController is a specialized controller for REST APIs where return values are automatically serialized to JSON.
package org.springframework.web.bind.annotation;
@Controller @ResponseBody
public @interface RestController {
   @AliasFor(annotation = Controller.class)
   String value() default "";
}
      
@Service on interface β†’ ❌ No bean created @Service on implementation classes β†’ βœ… Beans are created and managed by Spring.
@Component
public @interface Service {
   @AliasFor(annotation = Component.class)
   String value() default "";
}
      
- @Repository on interface that extend JpaRepository β†’ βœ… Bean created at runtime by Spring Data.
- @Repository on implementation classes β†’ βœ… Beans are created and managed by Spring.
- Adds exception translation (DataAccessException, PersistenceExceptionTranslationPostProcessor) for DAO layer.
@Component
public @interface Repository {
   @AliasFor(annotation = Component.class)
   String value() default "";
}
      
Extra to handle PersistanceException



Spring Boot Actuator wiki

Spring Boot Actuator provides production-ready endpoints to monitor and manage the health, metrics, and behavior of a running Spring Boot application.

Actuator = Monitor + Manage

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId> <!-- Required for HTTP exposure -->
</dependency>
Common Actuator Endpoints and Its details, Why Actuator Can Be a Security Risk
Endpoint Purpose
/actuator/health Application health (UP / DOWN)
/actuator/info App information
/actuator/metrics Performance metrics
/actuator/env Environment properties
/actuator/beans All Spring beans

Request : http://localhost:8080/actuator/health Response: { "status": "UP" }

Why Actuator is Important

  • Used in production monitoring
  • Integrates with monitoring tools (Prometheus, Grafana)
  • Helps DevOps and support teams
  • Useful for microservices health checks

Why Actuator Can Be a Security Risk

Spring Boot Actuator exposes internal application details.
If these endpoints are publicly accessible, attackers can gain sensitive information or even control parts of the application.

Spring Boot is secure by default:

  • Only /health and /info are exposed over HTTP
  • Other endpoints are disabled or protected
  • /shutdown is disabled by default

Best Practices to Secure Actuator πŸ”: Actuator endpoints can expose sensitive application data, so they must be restricted, secured, or disabled to prevent unauthorized access in production.

# Expose Only What You Need
management.endpoints.web.exposure.include=health,info

# Use Separate Port (Recommended)
management.server.port=9090

# Require authentication, Restrict access to admin roles only
management.endpoint.health.show-details=when_authorized

# Disable Dangerous Endpoints
management.endpoint.shutdown.enabled=false
Actuator Endpoint Information Exposed Security Risk
/actuator/env Environment variables, config values Leaks secrets like DB URLs, usernames, API keys
/actuator/beans All Spring bean definitions Reveals internal application structure
/actuator/threaddump Thread execution details Helps attackers analyze system behavior
/actuator/heapdump JVM memory snapshot Memory data leak, may expose sensitive data
/actuator/shutdown Application control Can stop the application remotely
/actuator/mappings All request mappings Reveals all available APIs

Spring AOP wiki

Spring AOP (Aspect-Oriented Programming) allows you to modularize cross-cutting concernsβ€”like logging, security, or transactionsβ€”separately from your core business logic.

Spring AOP applies cross-cutting logic to methods using proxies at runtime. πŸ‘‰ It adds extra behavior to methods without changing the actual code.

Important

πŸ“Œ @EnableAutoConfiguration reacts mainly to Spring Boot starters, not plain Spring libraries.

spring-boot-starter-aop Spring Boot (Recommended) Adding spring-aspects only provides AOP APIs:
@EnableAspectJAutoProxy is required to activate proxy-based AOP.
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
      
πŸ‘‰ Auto-configures AOP (no annotation needed)
To enable @AspectJ support with Java @Configuration add the @EnableAspectJAutoProxy annotation
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
</dependency>
      
@Configuration
@EnableAspectJAutoProxy
public class AppConfig { }
      
πŸ‘‰ Required to enable AOP

Key components of Aspect-Oriented Programming (AOP):

Concept Code Representation Explanation
Aspect @Aspect on LoggingAspect class A class that encapsulates advices and pointcuts (cross-cutting logic)
Join Point Parameter JoinPoint joinPoint in advice methods A point in execution like method call or exception throw
Pointcut @Pointcut("execution(...)") An expression that matches join points
Advice @Before, @After, @AfterReturning, @AfterThrowing, @Around The actual code executed at the matched join point

⚠️ **GitHub.com Fallback** ⚠️