I'm always excited to take on new projects and collaborate with innovative minds.

Email

contact@niteshsynergy.com

Website

https://www.niteshsynergy.com/

Spring Boot & Data JPA

Here’s a complete and in-depth explanation of Spring Boot:

Spring Boot is a Java-based framework that simplifies the process of developing Spring applications, especially web applications and microservices . It makes it easier to get started with Spring by providing pre-configured dependencies, auto-configuration, and other features that streamline development. Spring Boot also allows for creating stand-alone applications with minimal configuration, making it easier to deploy and manage.   

 
 
Here's a more detailed breakdown: 
  • Simplified Configuration:

    Spring Boot reduces the amount of configuration needed for Spring applications, allowing developers to focus on the application's logic rather than infrastructure details.   

     
  • Auto-Configuration:

    Spring Boot automatically configures many aspects of a Spring application, such as the web server (Tomcat, Jetty, Undertow) and data access libraries, based on the dependencies included in the project.   

     
  • Stand-alone Applications:

    Spring Boot enables the creation of stand-alone, executable applications that can be run using java -jar or traditional WAR deployments.   

     
  • Opinionated Defaults:

    Spring Boot provides sensible defaults for various Spring features, allowing developers to get started quickly and only customize the application as needed.   

     
  • Embedded Servers:

    Spring Boot allows embedding servers like Tomcat, Jetty, or Undertow directly into the application, eliminating the need for external server deployments.   

     
  • Production-Ready Features:

    Spring Boot includes features like metrics, health checks, and externalized configuration, which are useful for building production-ready applications.   

     
  • No XML or Code Generation:

    Spring Boot generally does not require XML configuration or code generation, making it a more modern and efficient approach to Spring development.   

     
  • Support for Multiple Languages:
    Spring Boot supports Java, Kotlin, and Apache Groovy.
     
     

    1. Spring vs Spring Boot

    FeatureSpring FrameworkSpring Boot
    DefinitionA lightweight Java framework for building enterprise applications.An extension of Spring that simplifies setup, configuration, and deployment.
    SetupRequires manual configuration of dependencies, XML/Java config, servlet setup, etc.Auto-configures everything; embedded servers like Tomcat/Jetty; minimal setup.
    BoilerplateNeeds a lot of boilerplate code.Eliminates boilerplate code.
    DeploymentRequires deploying WAR to external servers.Can be run as a standalone JAR.
    FocusFlexibility and full control.Convention over configuration.
    Use CaseBest for complex, fine-tuned enterprise apps.Best for microservices and rapid application development.

     

     2. Why Spring Boot?

    • You don’t need to write lengthy configuration.
    • Automatically sets up things (e.g., database, MVC, REST, security).
    • Embedded servers like Tomcat so no need to deploy WARs.
    • Easier to create microservices.
    • Faster prototyping and production-ready apps.

     

     

     3. How Spring Boot Works Internally

    1. Auto-Configuration (@EnableAutoConfiguration):
      • Analyzes your classpath and auto-configures beans based on available libraries.
      • Example: If spring-boot-starter-web is added, it sets up Spring MVC, Jackson, embedded Tomcat, etc.
    2. Spring Boot Starters:
      • Predefined dependency sets for specific features.
      • E.g., spring-boot-starter-data-jpa, spring-boot-starter-security.
    3. Spring Boot Actuator:
      • Provides monitoring & metrics (e.g., health, logs, beans).
    4. CommandLineRunner & ApplicationRunner:
      • Hooks to run custom logic after Spring context initializes.
    5. Application.properties / application.yml:
      • Centralized configuration without external files.
    6. Embedded Server:
      • Runs directly using java -jar yourapp.jar.

     

     Step-by-Step Execution from @SpringBootApplication

    Step 1: Your Main Class

    @SpringBootApplication
    public class SpringbootstudyApplication {
       public static void main(String[] args) {
           SpringApplication.run(SpringbootstudyApplication.class, args);
       }
    }
     

    • SpringApplication.run() is the entry point.
    • It bootstraps the entire Spring context.
    • But what makes Spring Boot so “magic” is the @SpringBootApplication annotation.

     

     Step 2: What is @SpringBootApplication?

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(...)
    public @interface SpringBootApplication {}
     

     

    @SpringBootApplication is a meta-annotation — a combination of three critical Spring annotations:

    Step 3: @SpringBootConfiguration

    @SpringBootConfiguration
     

    • This is a specialization of @Configuration.
    • Tells Spring this class contains @Bean definitions.
    • It is part of the core Spring Framework (@Configuration) — just like you used in traditional Spring.

    ✅ It means: “This is the starting configuration class for Spring Boot.”

     Step 4: @EnableAutoConfiguration

    @EnableAutoConfiguration

       Core to Spring Boot's magic!

       This annotation triggers auto-configuration, i.e., Spring Boot will automatically configure beans based on:

           JAR dependencies (spring-boot-starter-data-jpa, spring-boot-starter-web, etc.)

           application.properties / application.yml

    Internally:

       It uses @Import(AutoConfigurationImportSelector.class) to dynamically load configuration classes from:

    META-INF/spring.factories (for Spring Boot 2.x)
    META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Spring Boot 3.x)

    These contain hundreds of lines like:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
    ...

    ✅ It means: “Based on the classpath and properties, configure Spring Boot for me.”

    Step 5: @ComponentScan(...)

    @ComponentScan(...)


       Enables component scanning starting from the package of your main() class.

       It looks for:

           @Component

           @Service

           @Repository

           @Controller, @RestController

           Any custom stereotype annotations

    So if your class is in com.nitesh.app, all subpackages (com.nitesh.app.*) will be scanned.

    ✅ It means: “Automatically discover and register Spring-managed beans.”

     Step 6: SpringApplication.run(...)

    When you call:

    SpringApplication.run(SpringbootstudyApplication.class, args);
     

    Internally it does:

    1. Creates an ApplicationContext (AnnotationConfigApplicationContext or ReactiveWebServerApplicationContext)
    2. Processes the annotations:
      • Finds @SpringBootApplication
      • Processes its meta-annotations: @EnableAutoConfiguration, @ComponentScan, @SpringBootConfiguration
    3. Loads all beans found in classpath
    4. Runs any ApplicationRunner or CommandLineRunner beans
    5. Starts embedded server (Tomcat/Jetty/Netty), if it's a web application
    6. Application is ready to serve requests (if web), or just run tasks (if CLI app).

     

     Example Flow -Behind the Scenes

    Let’s say your project has:

    • spring-boot-starter-web in pom.xml
    • Your class annotated with @RestController
    • application.properties has some custom port

    Then:

    1. @EnableAutoConfiguration sees spring-boot-starter-web on the classpath
    2. Loads DispatcherServletAutoConfiguration, EmbeddedServletWebServerFactoryAutoConfiguration, etc.
    3. Auto-configures:
      • DispatcherServlet
      • Tomcat as embedded container
      • REST Controllers
      • JSON Mapper (Jackson)
    4. Component scan finds your @RestController class
    5. Registers it as a bean in Spring context

     

    Common Myths in Industry

    ❌ Myth✅ Truth
    SpringBootApplication just does component scanIt does much more: configures app context, beans, embedded server, auto-config
    You must always use @ComponentScan separatelyNot required — @SpringBootApplication already includes it
    You must define beans manuallyNot with Spring Boot — starters + properties + auto-config handles it
    It doesn’t work without XMLModern Spring Boot doesn’t need XML at all. All Java-based config

    Final Note:

    • @SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
    • It starts the Spring context, auto-configures beans, and scans components from the main class’s package downward.
    • SpringApplication.run() kicks off this chain by loading the class, reading the annotations, creating the context, and booting the app.

     

     4. Benefits of Spring Boot

    • Auto Configuration
    • Microservices Ready
    • Embedded Servers
    • Faster Development
    • Production-Ready Metrics with Actuator
    • Spring Ecosystem Integration (JPA, Security, Cloud, Kafka)

     

     5. Where Can You Use Spring Boot?

    • Microservices architecture
    • RESTful APIs
    • Web applications (admin portals, dashboards)
    • Backend for mobile/web games
    • Internal tools and CRMs
    • Billing or Payment systems
    • Cloud-native apps (AWS, GCP, Azure)
    • IoT applications

     

     6. Dependency Injection (DI) vs Dependency Management (DM)

    FeatureDependency Injection (DI)Dependency Management (DM)
    FocusManaging object creation and wiring dependencies.Managing library versions and transitive dependencies.
    Spring RoleCore principle; uses @Autowired, @Component, etc.Handled via Maven/Gradle using spring-boot-starter-*
    AnalogyPlug-and-play of components.Handling which tools you need for your code.

     

     7. Types of Dependency Injection in Spring

    TypeDescriptionExample
    Constructor InjectionDependency passed via constructor.public PlayerService(GameEngine engine)
    Setter InjectionDependency passed via setter method.setGameEngine(GameEngine engine)
    Field InjectionUses @Autowired directly on fields.@Autowired GameEngine engine;

     

     8. Circular Dependency

    When two or more beans depend on each other in a way that creates a loop.

    class A {
       @Autowired
       B b;
    }
    class B {
       @Autowired
       A a;
    }

    Spring fails with CircularDependencyException unless you break the loop using @Lazy, @PostConstruct, or refactor.

    → Circular Dependency Sol:
    Solution 1: Using @Lazy

    @Component
    public class A {
       @Autowired
       @Lazy
       private B b;
    }

    @Component
    public class B {
       @Autowired
       private A a;
    }

     Best for soft-coupled components and avoids eager loading.

    Solution 2: Using @PostConstruct

    @Component
    public class A {
       private B b;

       @Autowired
       private B tempB;

       @PostConstruct
       public void init() {
           this.b = tempB;
       }
    }

    @Component
    public class B {
       @Autowired
       private A a;
    }
    → Useful when circular dependency can't be avoided but delayed assignment is possible.

    Solution 3: Using Refactor to break the cycle

    Do your own code.

     

    9. Setter vs Constructor Injection

    FeatureSetterConstructor
    Optional DependenciesGood for optionalConstructor fails if missing
    TestabilityNot good, harder to testBetter for testing
    ImmutabilityMutableImmutable
    Circular Dependency RiskMore tolerantSafer; detects early

     

    10. Gaming Example for DI Concepts

    Let’s design a simple backend for an online multiplayer RPG game:

    Classes:

    • GameEngine: Core class that controls gameplay.
    • PlayerService: Manages player profiles and states.
    • WeaponService: Manages player weapons.
    • InventoryService: Manages player inventory.
    • MatchService: Handles match sessions between players.

    Use Constructor Injection:

    @Service
    public class PlayerService {
       private final GameEngine engine;
       private final WeaponService weaponService;
       public PlayerService(GameEngine engine, WeaponService weaponService) {
           this.engine = engine;
           this.weaponService = weaponService;
       }
    }

    What if WeaponService also needs PlayerService?

    @Service
    public class WeaponService {
       private final PlayerService playerService;
       public WeaponService(@Lazy PlayerService playerService) {
           this.playerService = playerService;
       }
    }
    

    ⚠️ This is Circular Dependency, so @Lazy delays creation to break the loop.

    Injection TypeNeed @Autowired?Notes
    Constructor (1 only)❌ NoAuto-injected by default
    Constructor (multiple)✅ YesMust specify which one
    Setter✅ YesRequired for Spring to inject value
    Field✅ YesUsed directly on the field

     

    Summary Flow in Gaming App using Spring Boot

    1. Add spring-boot-starter-web, spring-boot-starter-data-jpa.
    2. Auto-config sets up MVC, REST Controllers.
    3. PlayerController handles API calls.
    4. DI injects PlayerService into PlayerController.
    5. PlayerService calls WeaponService, InventoryService.
    6. Repositories auto-wired via Spring Data JPA.
    7. Application runs in embedded Tomcat using java -jar.

     

    Imagine we are building a Multiplayer Game Backend in Spring Boot with:

    • GameEngine: Core game loop logic
    • PlayerService: Manages player profiles
    • WeaponService: Handles weapons
    • InventoryService: Manages items
    • MatchService: Starts/ends PvP battles

     

     1. Constructor Injection

    Best for:

    • Mandatory dependencies
    • Immutability
    • Testability
    • Avoiding circular dependencies

     Example Use Case in Gaming:

     

    @Service
    public class MatchService {
       private final GameEngine gameEngine;
       private final PlayerService playerService;
       public MatchService(GameEngine gameEngine, PlayerService playerService) {
           this.gameEngine = gameEngine;
           this.playerService = playerService;
       }
       public void startMatch(String playerId) {
           // Uses playerService & gameEngine to start match
       }
    }
    

    ✅ Why:

    • Match must have GameEngine and PlayerService — no match can start otherwise.
    • Enforces correct construction at compile time.
    • Easy to test with mocks.

     

     2. Setter Injection

    Best for:

    • Optional dependencies
    • Configurable or replaceable logic
    • Circular dependency workaround (not preferred, but used)

     Example Use Case in Gaming:

    @Service
    public class InventoryService {
       private WeaponService weaponService;
       @Autowired
       public void setWeaponService(WeaponService weaponService) {
           this.weaponService = weaponService;
       }
       public void showWeapons(String playerId) {
           // Optional: weaponService may be null for basic players
       }
    }
    

    ✅ Why:

    • Weapon system may be disabled in demo mode, so InventoryService can work without it.
    • Use in dev/test environments where weapons are not initialized.

     

     3. Field Injection

    Best for:

    • Fast prototyping
    • When testability or immutability are not concerns

     Example Use Case in Gaming:

    @Service
    public class NotificationService {
       @Autowired
       private PlayerService playerService;
       public void notifyPlayer(String playerId, String message) {
           playerService.sendMessage(playerId, message);
       }
    }
    

    ❌ Why It’s Not Ideal:

    • Harder to test (no constructor to inject mocks)
    • No clear visibility of dependencies
    • Cannot mark as final — leads to mutable objects
    • Hides dependencies — makes code harder to maintain

     Summary 

    Injection TypeUse WhenGaming ExampleProsCons
    ConstructorMandatory dependencyMatchService, GameEngineImmutable, testableBreaks with circular dependencies
    SetterOptional dependencyInventoryService uses WeaponService optionallyFlexible, supports circularVerbose, less safe
    FieldFast dev, low priorityNotificationService uses PlayerServiceClean, fastPoor testability, hidden deps

     

    🔹 1. @SpringBootApplication

    What it does:

    Shortcut for:

    @Configuration
    @EnableAutoConfiguration
    @ComponentScan
     

    @SpringBootApplication
    public class BankApp {
       public static void main(String[] args) {
           SpringApplication.run(BankApp.class, args);
       }
    }
    

    ✅ Why:

    Bootstraps your whole application — like starting a Banking Core System server.

    🔹 2. @ComponentScan

    What it does:

    Scans specified packages for Spring beans (@Component, @Service, @Controller, etc.)

    📦 Use Case:

    @SpringBootApplication
    @ComponentScan(basePackages = "com.bank.loan")
    public class BankApp { ... }
    

    ✅ Why:

    If LoanService is in a different package (com.bank.loan), you tell Spring to look there.

    🔹 3. @EnableAutoConfiguration

    What it does:

    Automatically configures beans based on dependencies (like DataSource, Web, etc.)

    📦 Use Case:

    @EnableAutoConfiguration
    public class BankAppConfig { ... }
    

    🔹 4. @SpringBootConfiguration

    What it does:

    Same as @Configuration, but specific to Spring Boot.

    📦 Use in rare cases:

    When you want a class to be the root configuration, but not as the main class.

    @SpringBootConfiguration
    public class BankAppConfig {
       // Bean definitions
    }
    

    🔹 5. @RestController vs @Controller

    AnnotationUsed forReturnsExample
    @RestControllerREST APIsJSON/XML/api/account/balance
    @ControllerMVC/Web PagesHTML (view name)/login, /dashboard

     

    @RestController
    @RequestMapping("/api/account")
    public class AccountRestController {
       
       @GetMapping("/balance")
       public double getBalance() {
           return 10500.75;
       }
    }
    
    @Controller
    public class AccountWebController {
       @GetMapping("/dashboard")
       public String showDashboard() {
           return "dashboard"; // returns dashboard.html
       }
    }
    

     

     Path Param vs Query Param vs RequestParam vs PathVariable.

    ✅ Full Comparison Table with Code

    FeaturePath ParamQuery Param@RequestParam@PathVariable
    DefinitionPart of the URL pathAppended to the URL after ?Spring annotation to access query/form parametersSpring annotation to access path-based variables
    URL Format/users/101/users?id=101/users?id=101/users/101
    Used ForIdentify a specific resourceProvide optional or filtering dataAccept query/form dataIdentify a specific resource
    Mandatory?Usually yesOptionalOptional by defaultRequired by default
    Annotation Required?NoNo✅ Yes✅ Yes
    Can Accept Map?❌ No✅ Yes✅ Yes✅ Yes
    Used InRESTful API routingFiltering, pagination, searchForm submissions, search filtersRouting, REST APIs
    ✅ Sample Spring Boot Codejava @GetMapping("/users/{id}") public String getUser(@PathVariable int id) { return "User ID: " + id; }java @GetMapping("/users") public String getUser(@RequestParam int id) { return "User ID: " + id; }java @GetMapping("/search") public String search(@RequestParam String name, @RequestParam int age) { return "Name: " + name + ", Age: " + age; }java @GetMapping("/products/{category}/{id}") public String getProduct(@PathVariable Map<String, String> pathVars) { return pathVars.toString(); }

     

     

    🔹 1. @PathVariable

    Used to extract values from the URL path.

    📦 Banking Example:

    @GetMapping("/account/{accNo}")
    public String getAccount(@PathVariable String accNo) {
       return "Details for Account: " + accNo;
    }
    

    URL → /account/123456
    accNo = 123456

    🔹 2. @RequestParam

    Used to extract query parameters from the URL.

    📦 Example:

    @GetMapping("/loan/search")
    public String searchLoan(@RequestParam String type, @RequestParam int duration) {
       return "Searching for " + type + " loans for " + duration + " years";
    }
    

    🔹 3. @RequestBody

    Used to accept full JSON body in POST or PUT.

    📦 Example:

    @PostMapping("/account")
    public String createAccount(@RequestBody Account account) {
       return "Account created for " + account.getName();
    }
    

    🔹 4. @RequestHeader

    Extract values from the header of the HTTP request.

    📦 Example:

    @GetMapping("/validate")
    public String validate(@RequestHeader("auth-token") String token) {
       return "Token received: " + token;
    }
    

     

    ✅ Summary Table

    AnnotationExtracts FromExample URL / Use
    @PathVariableURL path/account/123
    @RequestParamQuery string/loan?type=home
    @RequestBodyJSON bodyPOST /account
    @RequestHeaderHeadersauth-token

     

    🔧 1. Exclude Auto-Configuration (e.g., DB)

    If you don't want Spring Boot to auto-configure a database (like H2, DataSource, or JPA):

    🔹 Way 1: Using exclude in @SpringBootApplication

    @SpringBootApplication(exclude = {
       DataSourceAutoConfiguration.class,
       HibernateJpaAutoConfiguration.class
    })
    public class BankApp { ... }
    

    🧠 Used in Microservices that don’t use DB, or use custom DB clients (MongoTemplate, JDBC manually, etc.)

    🔹 Way 2: Using application.properties

    spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
     

    🌐 2. Custom Embedded Server (e.g., Jetty, Undertow)

    Spring Boot uses embedded Tomcat by default.

    🟢 To switch to Jetty:

    1. Remove Tomcat dependency (if declared):
    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
     <exclusions>
       <exclusion>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
       </exclusion>
     </exclusions>
    </dependency>

    Add Jetty dependency:

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

    You can similarly use Undertow if you prefer lightweight, fast startups for reactive systems.

    🚀 3. How Spring Boot works in main() method

    public class MyBankApp {
       public static void main(String[] args) {
           SpringApplication.run(MyBankApp.class, args);
       }
    }
     

    ✅ What Happens Behind the Scenes:

    🔸 Step-by-Step:

    1. Creates SpringApplication instance
    2. Loads ApplicationContext
    3. Scans & Instantiates Beans
    4. Starts Embedded Server (Tomcat/Jetty)
    5. Attaches Application Listeners
    6. Registers Shutdown Hooks
    7. Main thread becomes non-daemon to keep the app running

    🧵 4. Threading Behind the main()

    ✅ Main Thread

    • The thread you see in main() is non-daemon
    • Keeps the application alive
    • Starts embedded server thread (Tomcat/Jetty/Undertow)

    ✅ Daemon Threads (Internally Used)

    • Spring Boot starts many daemon threads, including:
      • background-preinitializer
      • Tomcat-Acceptor-*
      • Tomcat-Nio-*
      • Scheduling threads (for @Scheduled)
      • AsyncExecutor threads (if enabled)

    🎮 Example Analogy (Game Server):

    • Main Thread = Launches the game engine.
    • Game Loop Thread (non-daemon) = Keeps the game running.
    • Matchmaking Thread (daemon) = Runs in background.
    • Shutdown Hook Thread = Cleans up resources when server is stopped.

    📦 How You Can Hook into Startup or Threads:

     
    @Component
    public class StartupTask implements CommandLineRunner {
       @Override
       public void run(String... args) {
           System.out.println("Banking server booted at " + LocalDateTime.now());
       }
    }
    

     

    Or:

    @Bean
    public ApplicationRunner customRunner() {
       return args -> {
           System.out.println("Executed after Spring Context ready.");
       };
    }
     

    🛡 Optional: Disable Web Environment

    If you want to use Spring Boot without web (no server):

    public static void main(String[] args) {
       new SpringApplicationBuilder(MyBankApp.class)
           .web(WebApplicationType.NONE)
           .run(args);
    }
     

    Useful for:

    • CLI tools
    • Batch jobs
    • Microservices without HTTP layer

     

    Let's build a Spring Boot + H2 in-memory POC for a Bank Statement Feature, where a user can:

    1. Fetch transactions for the current month
    2. Fetch transactions by a specific month (e.g., March 2025)
    3. Fetch transactions between a date range

    ✅ STACK:

    • Spring Boot
    • H2 In-Memory DB
    • Spring Data JPA
    • REST API

    🔖 ENTITY: Transaction

    @Entity
    public class Transaction {

       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Long id;

       private String accountNumber;

       private String description;

       private Double amount;

       private LocalDate transactionDate;

       private String transactionType; // CREDIT / DEBIT

       // Getters, Setters, Constructors
    }
     

    📦 REPOSITORY: TransactionRepository

    @Repository
    public interface TransactionRepository extends JpaRepository<Transaction, Long> {

       // 1. Transactions for current month
       @Query("SELECT t FROM Transaction t WHERE MONTH(t.transactionDate) = MONTH(CURRENT_DATE) AND YEAR(t.transactionDate) = YEAR(CURRENT_DATE)")
       List<Transaction> findCurrentMonthTransactions();

       // 2. Transactions for a specific month & year
       @Query("SELECT t FROM Transaction t WHERE MONTH(t.transactionDate) = :month AND YEAR(t.transactionDate) = :year")
       List<Transaction> findByMonthAndYear(@Param("month") int month, @Param("year") int year);

       // 3. Transactions between date range
       List<Transaction> findByTransactionDateBetween(LocalDate from, LocalDate to);
    }
     

    ⚙️ SERVICE: TransactionService

    @Service
    public class TransactionService {

       @Autowired
       private TransactionRepository transactionRepository;

       public List<Transaction> getCurrentMonthTransactions() {
           return transactionRepository.findCurrentMonthTransactions();
       }

       public List<Transaction> getByMonthAndYear(int month, int year) {
           return transactionRepository.findByMonthAndYear(month, year);
       }

       public List<Transaction> getByDateRange(LocalDate start, LocalDate end) {
           return transactionRepository.findByTransactionDateBetween(start, end);
       }
    }
     

    🌐 CONTROLLER: TransactionController

    @RestController
    @RequestMapping("/api/transactions")
    public class TransactionController {

       @Autowired
       private TransactionService transactionService;

       // 1. Current month transactions
       @GetMapping("/current")
       public List<Transaction> getCurrentMonthTransactions() {
           return transactionService.getCurrentMonthTransactions();
       }

       // 2. By specific month/year
       @GetMapping("/month")
       public List<Transaction> getByMonthYear(
           @RequestParam int month,
           @RequestParam int year) {
           return transactionService.getByMonthAndYear(month, year);
       }

       // 3. By date range
       @GetMapping("/range")
       public List<Transaction> getByDateRange(
           @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
           @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
           return transactionService.getByDateRange(from, to);
       }
    }
     

    🧪 Sample Requests (Postman / Curl):

    1. Current month

    GET /api/transactions/current
     

    By month (e.g., March 2025)

    GET /api/transactions/month?month=3&year=2025
     

    By range:

    GET /api/transactions/range?from=2025-03-01&to=2025-03-31
     

    🛠 application.properties

    spring.datasource.url=jdbc:h2:mem:testdb
    spring.datasource.driverClassName=org.h2.Driver
    spring.datasource.username=sa
    spring.datasource.password=

    spring.h2.console.enabled=true
    spring.jpa.show-sql=true
    spring.jpa.hibernate.ddl-auto=create
    spring.h2.console.path=/h2-console
     

    🧪 Insert Test Data on Startup

    @Component
    public class DataSeeder implements CommandLineRunner {

       @Autowired
       private TransactionRepository repo;

       @Override
       public void run(String... args) throws Exception {
           repo.save(new Transaction(null, "123456", "Salary", 50000.0, LocalDate.now().withDayOfMonth(5), "CREDIT"));
           repo.save(new Transaction(null, "123456", "Grocery", -5000.0, LocalDate.now().withDayOfMonth(10), "DEBIT"));
           repo.save(new Transaction(null, "123456", "Rent", -15000.0, LocalDate.of(2025, 3, 1), "DEBIT"));
           repo.save(new Transaction(null, "123456", "Gift", 2000.0, LocalDate.of(2025, 2, 25), "CREDIT"));
       }
    }
     

     

     

    Next →

     

    3️⃣ Spring Boot Auto-Configuration Explained in Depth


    1️⃣ What is Auto-Configuration?

    Auto-Configuration in Spring Boot means that Spring Boot attempts to automatically configure your Spring application based on the dependencies and classes available on your classpath.

    • Instead of you manually defining beans and settings (like database datasource, MVC config, Jackson JSON, etc.),
    • Spring Boot tries to guess and create those beans for you if you have certain libraries in your project.

    Why Auto-Configuration?

    • Speeds up development
    • Removes boilerplate XML or Java config
    • Uses sensible defaults, but can be customized
    • Makes Spring “opinionated” but flexible

    2️⃣ How Auto-Configuration Works Internally?

    Main flow:

    1. Enable Auto-Configuration:

      When you use @SpringBootApplication, it includes @EnableAutoConfiguration which triggers Spring Boot auto-config.

    2. Look for Auto-Configuration Classes:

      Spring Boot scans META-INF/spring.factories files from all JAR dependencies.
      It looks for all classes listed under the key:
      org.springframework.boot.autoconfigure.EnableAutoConfiguration

    3. Evaluate Conditions:

      Each auto-config class is annotated with conditional annotations like:

      • @ConditionalOnClass (load only if a certain class is on the classpath)
      • @ConditionalOnBean (only if some bean is already defined)
      • @ConditionalOnMissingBean (only if no other bean of the same type exists)
      • @ConditionalOnProperty (enable only if specific properties are set)
    4. Apply Configurations:

      If all conditions pass, the auto-config class creates beans and configures the context.

     

    Diagram (Simplified):

     

    image-236.png

     

     

    3️⃣ spring.factories and spring/org.springframework.boot.autoconfigure

    What is spring.factories?

    • It's a file located under META-INF/ inside Spring Boot JARs and your dependencies.
    • It lists fully qualified class names of auto-configuration classes that Spring Boot should consider.

    Example of spring.factories entry:

    # org.springframework.boot.autoconfigure.EnableAutoConfiguration= lists classes for auto-config
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
     

    How it works:

    • Spring Boot's auto-configuration loader reads these entries and tries to load all these classes automatically.
    • Each class has bean definitions & conditional logic.

    Quick Example: DataSourceAutoConfiguration

    • When you add spring-boot-starter-jdbc or spring-boot-starter-data-jpa,
    • Spring Boot sees that javax.sql.DataSource class is present.
    • It loads DataSourceAutoConfiguration from the spring.factories.
    • This configures a DataSource bean if no other DataSource is defined by you.
    • It uses properties like spring.datasource.url, username, etc. from your application.properties.

     

     

    Overriding Auto-Configuration

    You can customize or disable auto-configuration:

    • Exclude specific auto-config classes

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    public class MyApp { ... }
     

     

    • Define your own beans

    Spring Boot will back off if it finds user-defined beans of the same type (thanks to @ConditionalOnMissingBean).

     

    Summary

    ConceptDescription
    Auto-ConfigurationSpring Boot auto-magically configures beans based on classpath & properties.
    @EnableAutoConfigurationActivates auto-configuration support
    spring.factoriesFile listing auto-configuration classes to load
    Conditional AnnotationsConditions on class presence, bean presence, properties, etc. to selectively apply auto-config
    CustomizationOverride by excluding auto-config classes or defining your own beans

     

    How to Create Custom Auto-Configuration in Spring Boot


    Why create custom auto-configuration?

    • You build reusable libraries/starter projects that automatically configure themselves when added as a dependency.
    • Makes your library plug-and-play with zero or minimal setup for users.
    • Mimics how Spring Boot starter modules work (spring-boot-starter-web, spring-boot-starter-data-jpa, etc.).

    Step 1: Create a Spring Boot Starter Module (or regular jar)

    Create a new project (can be a separate maven module or jar) that will hold your auto-configuration.


    Step 2: Write Your Auto-Configuration Class

    Create a Java config class with @Configuration. Annotate it with @ConditionalOnClass, @ConditionalOnMissingBean, or other conditional annotations to make it smart.

    Example: Suppose you want to auto-configure a simple service bean MyService only if the class com.example.service.MyService is on the classpath.

     

    package com.example.autoconfig;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;

    @Configuration
    @ConditionalOnClass(name = "com.example.service.MyService")
    public class MyServiceAutoConfiguration {

       @Bean
       @ConditionalOnMissingBean
       public MyService myService() {
           return new MyService();
       }
    }
     

     

    Step 3: Create the spring.factories file

    Create the file in your resources folder:

    src/main/resources/META-INF/spring.factories
     

    Add this content:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.example.autoconfig.MyServiceAutoConfiguration
     

     

    Step 4: Package and use it

    • Package your module as a jar.
    • Add it as a dependency in any Spring Boot application.
    • When Spring Boot starts, it will load your auto-configuration class automatically, creating MyService bean if the conditions are met.

    Step 5: Test the auto-configuration

    Create a test Spring Boot app, add your jar, and check if the bean is injected automatically.

     

    Use Conditional Properties

    You can add @ConditionalOnProperty to enable/disable your auto-config via properties.

    @ConditionalOnProperty(name = "my.service.enabled", havingValue = "true", matchIfMissing = true)
     

    This way, users can control your auto-config by adding:

    my.service.enabled=false
     

     

    Next → 

     

    4️⃣ Spring Boot Starters


    What are Starters?

    Starters are convenient dependency descriptors provided by Spring Boot.
    They bundle a set of related dependencies you usually need for a certain functionality into one single dependency.

    Why Starters?

    • Avoid manual dependency management
    • Easily add complete features (web, JPA, security, etc.)
    • Ensure compatible versions of dependencies

    Common Starters Examples

    Starter DependencyPurpose
    spring-boot-starter-webBuild RESTful web applications with Spring MVC and embedded Tomcat
    spring-boot-starter-data-jpaSpring Data JPA with Hibernate for DB access
    spring-boot-starter-securityAdds Spring Security for authentication/authorization
    spring-boot-starter-testTesting libraries (JUnit, Mockito, etc.)

     

    Example: Adding spring-boot-starter-web

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

    This adds everything to build REST controllers, handle JSON (Jackson), and embed Tomcat server.

     

     

    Next →

    Steps to Create a Custom Spring Boot Starter in Java

    1. Create a new Maven/Gradle project

    This project will be your starter module, e.g. mycompany-spring-boot-starter-foo.

    2. Define dependencies in your starter

    • In your starter’s pom.xml or build.gradle, add dependencies that you want to expose to users.
    • Mark some dependencies as compile or implementation (to be transitive).
    • Add spring-boot-autoconfigure as a dependency with provided or normal scope because you will create auto-config classes.

    Example in Maven pom.xml:

    <dependencies>
       <!-- The library/dependencies you want to bundle -->
       <dependency>
           <groupId>com.example</groupId>
           <artifactId>foo-library</artifactId>
           <version>1.0.0</version>
       </dependency>

       <!-- Required for auto-configuration -->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-autoconfigure</artifactId>
           <version>${spring.boot.version}</version>
       </dependency>
    </dependencies>
     

    3. Create your auto-configuration class

    • Create a class annotated with @Configuration and @ConditionalOnXXX annotations (like @ConditionalOnClass, etc.) to activate your config only if dependencies are present.
    • Use @AutoConfigureAfter or @AutoConfigureBefore if needed.
    • Use @EnableConfigurationProperties if you want to bind properties.

    Example:

    package com.example.foo.autoconfigure;

    import com.example.foo.FooService;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    @Configuration
    @ConditionalOnClass(FooService.class)  // Enable only if FooService is on classpath
    public class FooAutoConfiguration {

       @Bean
       @ConditionalOnMissingBean
       public FooService fooService() {
           return new FooService();
       }
    }
     

    4. Register your auto-configuration class in spring.factories

    • Create a src/main/resources/META-INF/spring.factories file.
    • Register your auto-config class under key:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.example.foo.autoconfigure.FooAutoConfiguration
     

    5. (Optional) Provide spring-configuration-metadata.json

    • To allow IDE support for your starter’s configuration properties.
    • Use @ConfigurationProperties and generate metadata via spring-boot-configuration-processor.

    6. Build and install your starter jar

    mvn clean install
     

    7. Use your custom starter in other projects

    Just add your starter dependency:

    <dependency>
       <groupId>com.example</groupId>
       <artifactId>mycompany-spring-boot-starter-foo</artifactId>
       <version>1.0.0</version>
    </dependency>
     

    When your app runs, Spring Boot will pick your auto-config and configure your beans.

     

    Next →

    5️⃣ Spring Boot CLI


    What is Spring Boot CLI?

    • A command-line tool to quickly create, run, and test Spring Boot apps without the full IDE.
    • Supports running apps written in Groovy or Java.

    Installing Spring Boot CLI

    • Download from Spring’s site or install via SDKMAN or Homebrew (macOS).

    sdk install springboot
    # or
    brew install springboot
     

     

     

    6️⃣ Configuration Management


    application.properties / application.yml

    • The main way to externalize configuration.
    • Can use .properties or .yml format.

    Example: application.properties

    game.leaderboard.max-players=100
    game.leaderboard.timezone=UTC
     

    Profile-specific Properties

    • For different environments (dev, test, prod), use profiles.
    • Create files like application-dev.properties, application-prod.yml.
    • Activate profile with -Dspring.profiles.active=dev

    Environment-specific configuration

    • Profiles can override default properties.
    • Useful to switch DB URL, logging level, etc. per environment.

    Reading config using @Value and @ConfigurationProperties

    Using @Value

    @Component
    public class GameSettings {
       @Value("${game.leaderboard.max-players}")
       private int maxPlayers;
    }
     

    Using @ConfigurationProperties

    Better for grouping related props.

    @Component
    @ConfigurationProperties(prefix = "game.leaderboard")
    public class LeaderboardConfig {
       private int maxPlayers;
       private String timezone;

       // getters & setters
    }
     

    Gaming Use Case - Example

    You have a leaderboard service that needs to:

    • Limit max players (max-players)
    • Support multiple regions with different timezones (timezone)
    • Change limits per environment (e.g., smaller limit in dev)

    application-dev.yml

    game:
     leaderboard:
       max-players: 10
       timezone: "America/New_York"
     

    application-prod.yml

    game:
     leaderboard:
       max-players: 1000
       timezone: "UTC"
     

    Summary Table

    ConceptDescriptionExample Use Case (Gaming)
    StartersPre-bundled dependenciesAdd web, JPA, security starters for leaderboard app
    CLIQuick prototyping using command lineRun simple Groovy API for player scores
    application.propertiesExternal config file for app settingsSet max leaderboard size, timezone
    ProfilesEnv-specific config overrideDifferent limits in dev and prod
    @ValueInject single propertyInject maxPlayers directly into a bean
    @ConfigurationPropertiesInject multiple related properties groupedGroup leaderboard configs into a config bean

     

    7️⃣ Spring Boot Profiles → 

    Please visit  on if you wish shortcut study →https://niteshsynergy.com/spring-boot-profile


    Else→

     

    7️⃣ Spring Boot Profiles — In Depth

     

    What are Profiles?

    • Profiles in Spring Boot allow you to group configuration and beans that should only be active in specific environments or contexts.
    • They help you switch between configurations easily for Dev, Test, UAT, Production, etc.
    • Avoids hardcoding environment-specific settings in the app.
    • Makes your app flexible and environment aware.

    How Spring Profiles Work

    • You create multiple config files named like application-{profile}.properties or .yml.
    • You can annotate beans with @Profile("profileName") so those beans only load when that profile is active.
    • You activate profiles using:
      • JVM argument: -Dspring.profiles.active=profileName
      • Environment variable: SPRING_PROFILES_ACTIVE=profileName
      • Programmatically via code or config files

     

     

    Example Scenario: Multiple DB Configs

    • Test: Use MySQL
    • Production: Use MongoDB
    • UAT (User Acceptance Test): Use H2 (In-memory DB)

    Step 1: Define Profiles and Config Files

    Create separate config files for each profile:

     

    application-test.yml (MySQL)

     

    spring:
     datasource:
       url: jdbc:mysql://localhost:3306/testdb
       username: testuser
       password: testpass
     jpa:
       hibernate:
         ddl-auto: update
       show-sql: true
     

    application-prod.yml (MongoDB)

    application-uat.yml (H2 In-memory DB)

    spring:
     datasource:
       url: jdbc:h2:mem:uatdb;DB_CLOSE_DELAY=-1
       driverClassName: org.h2.Driver
       username: sa
       password: password
     jpa:
       hibernate:
         ddl-auto: create-drop
       show-sql: true
     

    Step 2: Create Beans with @Profile

    If you want to define separate beans depending on profile, annotate them:

    @Configuration
    public class DataSourceConfig {

       @Bean
       @Profile("test")
       public DataSource mysqlDataSource() {
           // configure and return MySQL DataSource
       }

       @Bean
       @Profile("prod")
       public MongoClient mongoClient() {
           // configure and return MongoDB client
       }

       @Bean
       @Profile("uat")
       public DataSource h2DataSource() {
           // configure and return H2 DataSource
       }
    }
     

    Step 3: Activate Profiles

    You can activate profiles in multiple ways:

    • CLI or JVM args

    java -jar app.jar --spring.profiles.active=test
    # or
    java -jar app.jar -Dspring.profiles.active=prod
     

    application.properties (default profile)

    spring.profiles.active=uat
     

    Environment variable

    export SPRING_PROFILES_ACTIVE=prod
     

    Step 4: Example: Banking Application Fetching Transactions (with Profiles)

    You want your banking app to fetch transactions from different databases depending on environment.

    • On test, transactions come from MySQL
    • On prod, transactions come from MongoDB
    • On uat, use H2 for fast testing

    The service layer can stay the same, Spring injects the correct datasource/bean based on profile.

     

    Code Example: Repository Interface

    public interface TransactionRepository {
       List<Transaction> findByUserIdAndDateRange(String userId, LocalDate start, LocalDate end);
    }
     

    MySQL Implementation (Test Profile)

    @Repository
    @Profile("test")
    public class MysqlTransactionRepository implements TransactionRepository {
       // Use JdbcTemplate or JPA with MySQL connection
    }
     

    MongoDB Implementation (Prod Profile)

    @Repository
    @Profile("prod")
    public class MongoTransactionRepository implements TransactionRepository {
       // Use MongoTemplate or MongoRepository here
    }
     

    H2 Implementation (UAT Profile)

    @Repository
    @Profile("uat")
    public class H2TransactionRepository implements TransactionRepository {
       // Use JdbcTemplate or JPA with H2 DB
    }
     

    Complete Spring Boot Example: Banking Transactions with Profiles & Multiple DBs

     

    Project Structure:

    src/main/java/com/example/banking
    ├─ controller
    │    └─ TransactionController.java
    ├─ service
    │    └─ TransactionService.java
    ├─ repository
    │    ├─ TransactionRepository.java  (interface)
    │    ├─ MysqlTransactionRepository.java (@Profile test)
    │    ├─ MongoTransactionRepository.java (@Profile prod)
    │    └─ H2TransactionRepository.java (@Profile uat)
    ├─ model
    │    └─ Transaction.java
    ├─ config
    │    └─ DataSourceConfig.java
    └─ BankingApplication.java
     

    1. Model - Transaction.java

    package com.example.banking.model;

    import java.time.LocalDate;

    public class Transaction {
       private String id;
       private String userId;
       private LocalDate date;
       private double amount;
       private String description;

       // getters and setters

       public Transaction() {}

       public Transaction(String id, String userId, LocalDate date, double amount, String description) {
           this.id = id;
           this.userId = userId;
           this.date = date;
           this.amount = amount;
           this.description = description;
       }

       // Getters and setters below
    }
     

    2. Repository Interface

    package com.example.banking.repository;

    import com.example.banking.model.Transaction;

    import java.time.LocalDate;
    import java.util.List;

    public interface TransactionRepository {
       List<Transaction> findByUserIdAndDateRange(String userId, LocalDate start, LocalDate end);
    }
     

    3. MySQL Implementation (test profile)

    package com.example.banking.repository;

    import com.example.banking.model.Transaction;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;

    import java.sql.ResultSet;
    import java.time.LocalDate;
    import java.util.List;

    @Repository
    @Profile("test")
    public class MysqlTransactionRepository implements TransactionRepository {

       private final JdbcTemplate jdbcTemplate;

       public MysqlTransactionRepository(JdbcTemplate jdbcTemplate) {
           this.jdbcTemplate = jdbcTemplate;
       }

       @Override
       public List<Transaction> findByUserIdAndDateRange(String userId, LocalDate start, LocalDate end) {
           String sql = "SELECT id, user_id, date, amount, description FROM transactions WHERE user_id = ? AND date BETWEEN ? AND ?";
           return jdbcTemplate.query(sql, (ResultSet rs, int rowNum) -> new Transaction(
                   rs.getString("id"),
                   rs.getString("user_id"),
                   rs.getDate("date").toLocalDate(),
                   rs.getDouble("amount"),
                   rs.getString("description")
           ), userId, java.sql.Date.valueOf(start), java.sql.Date.valueOf(end));
       }
    }
     

    4. MongoDB Implementation (prod profile)

    package com.example.banking.repository;

    import com.example.banking.model.Transaction;
    import org.springframework.context.annotation.Profile;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.query.Criteria;
    import org.springframework.data.mongodb.core.query.Query;
    import org.springframework.stereotype.Repository;

    import java.time.LocalDate;
    import java.util.List;

    @Repository
    @Profile("prod")
    public class MongoTransactionRepository implements TransactionRepository {

       private final MongoTemplate mongoTemplate;

       public MongoTransactionRepository(MongoTemplate mongoTemplate) {
           this.mongoTemplate = mongoTemplate;
       }

       @Override
       public List<Transaction> findByUserIdAndDateRange(String userId, LocalDate start, LocalDate end) {
           Query query = new Query();
           query.addCriteria(Criteria.where("userId").is(userId)
                   .andOperator(Criteria.where("date").gte(start), Criteria.where("date").lte(end)));
           return mongoTemplate.find(query, Transaction.class);
       }
    }
     

    5. H2 Implementation (uat profile)

    package com.example.banking.repository;

    import com.example.banking.model.Transaction;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;

    import java.sql.ResultSet;
    import java.time.LocalDate;
    import java.util.List;

    @Repository
    @Profile("uat")
    public class H2TransactionRepository implements TransactionRepository {

       private final JdbcTemplate jdbcTemplate;

       public H2TransactionRepository(JdbcTemplate jdbcTemplate) {
           this.jdbcTemplate = jdbcTemplate;
       }

       @Override
       public List<Transaction> findByUserIdAndDateRange(String userId, LocalDate start, LocalDate end) {
           String sql = "SELECT id, user_id, date, amount, description FROM transactions WHERE user_id = ? AND date BETWEEN ? AND ?";
           return jdbcTemplate.query(sql, (ResultSet rs, int rowNum) -> new Transaction(
                   rs.getString("id"),
                   rs.getString("user_id"),
                   rs.getDate("date").toLocalDate(),
                   rs.getDouble("amount"),
                   rs.getString("description")
           ), userId, java.sql.Date.valueOf(start), java.sql.Date.valueOf(end));
       }
    }
     

    6. Service Layer

    package com.example.banking.service;

    import com.example.banking.model.Transaction;
    import com.example.banking.repository.TransactionRepository;
    import org.springframework.stereotype.Service;

    import java.time.LocalDate;
    import java.util.List;

    @Service
    public class TransactionService {

       private final TransactionRepository transactionRepository;

       public TransactionService(TransactionRepository transactionRepository) {
           this.transactionRepository = transactionRepository;
       }

       public List<Transaction> getTransactionsByUserAndDateRange(String userId, LocalDate start, LocalDate end) {
           return transactionRepository.findByUserIdAndDateRange(userId, start, end);
       }
    }
     

    7. Controller

    package com.example.banking.controller;

    import com.example.banking.model.Transaction;
    import com.example.banking.service.TransactionService;
    import org.springframework.format.annotation.DateTimeFormat;
    import org.springframework.web.bind.annotation.*;

    import java.time.LocalDate;
    import java.util.List;

    @RestController
    @RequestMapping("/api/transactions")
    public class TransactionController {

       private final TransactionService transactionService;

       public TransactionController(TransactionService transactionService) {
           this.transactionService = transactionService;
       }

       // 1. Fetch transactions by month (year-month format)
       @GetMapping("/month")
       public List<Transaction> getTransactionsByMonth(
               @RequestParam String userId,
               @RequestParam int year,
               @RequestParam int month) {
           LocalDate start = LocalDate.of(year, month, 1);
           LocalDate end = start.withDayOfMonth(start.lengthOfMonth());
           return transactionService.getTransactionsByUserAndDateRange(userId, start, end);
       }

       // 2. Fetch transactions by custom date range
       @GetMapping("/range")
       public List<Transaction> getTransactionsByDateRange(
               @RequestParam String userId,
               @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate start,
               @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate end) {
           return transactionService.getTransactionsByUserAndDateRange(userId, start, end);
       }

       // 3. Fetch transactions for current month
       @GetMapping("/currentMonth")
       public List<Transaction> getTransactionsCurrentMonth(@RequestParam String userId) {
           LocalDate now = LocalDate.now();
           LocalDate start = now.withDayOfMonth(1);
           LocalDate end = now.withDayOfMonth(now.lengthOfMonth());
           return transactionService.getTransactionsByUserAndDateRange(userId, start, end);
       }
    }
     

    8. DataSourceConfig

    For MySQL and H2 datasource configuration:

    package com.example.banking.config;

    import com.mongodb.client.MongoClient;
    import com.mongodb.client.MongoClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;

    import javax.sql.DataSource;

    @Configuration
    public class DataSourceConfig {

       @Bean
       @Profile("test")
       public DataSource mysqlDataSource() {
           DriverManagerDataSource ds = new DriverManagerDataSource();
           ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
           ds.setUrl("jdbc:mysql://localhost:3306/testdb");
           ds.setUsername("testuser");
           ds.setPassword("testpass");
           return ds;
       }

       @Bean
       @Profile("uat")
       public DataSource h2DataSource() {
           DriverManagerDataSource ds = new DriverManagerDataSource();
           ds.setDriverClassName("org.h2.Driver");
           ds.setUrl("jdbc:h2:mem:uatdb;DB_CLOSE_DELAY=-1");
           ds.setUsername("sa");
           ds.setPassword("");
           return ds;
       }

       @Bean
       @Profile("prod")
       public MongoClient mongoClient() {
           return MongoClients.create("mongodb://prodUser:prodPass@prodHost:27017/proddb");
       }
    }
     

    9. Main Application Class

    package com.example.banking;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication
    public class BankingApplication {

       public static void main(String[] args) {
           SpringApplication.run(BankingApplication.class, args);
       }
    }
     

    10. application.yml

    spring:
     profiles:
       active: uat  # Change this to test, prod or uat to switch environment

    # Common configs can go here
     

     

    How To Run

    • Switch profile in application.yml or via command line:

    # Run with test profile (MySQL)
    mvn spring-boot:run -Dspring-boot.run.profiles=test

    # Run with prod profile (MongoDB)
    mvn spring-boot:run -Dspring-boot.run.profiles=prod

    # Run with uat profile (H2)
    mvn spring-boot:run -Dspring-boot.run.profiles=uat
     

     

    Next →

    8️⃣ Spring Boot DevTools — In Depth


    What is Spring Boot DevTools?

    • Spring Boot DevTools is a module that enhances the development experience by providing features like:
      • Automatic restart of your application on code changes.
      • LiveReload support to refresh your browser automatically.
      • Hot swapping for faster feedback.
      • Helpful developer-friendly error pages.
    • It is only intended for development, not production.

    How to Add DevTools?

    Add this dependency in your pom.xml or build.gradle:

    Maven

    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-devtools</artifactId>
     <optional>true</optional>
    </dependency>
     

    Gradle

    developmentOnly("org.springframework.boot:spring-boot-devtools")
     

     

    1. Hot Swapping

    • Hot swapping means you can update your code (e.g., Java classes, static resources) and see changes without restarting your JVM manually.
    • DevTools triggers automatic restart or reload of changed classes.
    • How it works internally:
      Spring Boot runs your app in a special classloader that watches your target/classes or build/classes folders. When a class changes, the classloader reloads the application context.

    2. Auto Restart

    • When you modify any class or resource, DevTools automatically restarts your app to apply changes.
    • It’s faster than a full restart because:
      • Only your app classes are reloaded (not libraries).
      • Uses two classloaders: one for static libraries (no reload), one for app classes (reload).
    • It watches specific folders (src/main/java, resources) by default.
    • Configuring Restart:

      You can exclude or include files from restart using spring.devtools.restart.exclude and spring.devtools.restart.additional-paths in application.properties.

    spring.devtools.restart.exclude=static/**,public/**
    spring.devtools.restart.additional-paths=src/main/webapp
     

     

    3. LiveReload

    • DevTools comes with built-in support for LiveReload.
    • When resources or templates change, it triggers your browser to reload automatically.
    • How to use:

      Just enable the LiveReload plugin/extension in your browser (available for Chrome/Firefox), or install a LiveReload client.

    • By default, LiveReload runs on port 35729.
    • You can disable LiveReload via:

    spring.devtools.livereload.enabled=false
     

     

    4. Developer-friendly Error Pages

    • When your app throws an exception, DevTools shows detailed error pages in the browser.
    • These pages contain:
      • Full stack trace.
      • Variables in scope.
      • Source code snippet around the error.
    • This is way more useful than generic 500 errors.
    • This is enabled by default in DevTools and disables when the app runs outside development mode.

    Example: Using DevTools in a Simple Spring Boot App

    1. Add devtools dependency.
    2. Run your app.
    3. Modify a controller or HTML template.
    4. Notice the app automatically restarts and your browser refreshes.

     

    Additional Tips

    • Disable caching in Thymeleaf templates during development to see instant updates:

    spring.thymeleaf.cache=false
     

    • Restart triggers:

      DevTools restarts only on changes to .class or .properties files. If you add new files, you might need a manual restart.

    • Remote Restart:

      DevTools supports remote restart where you can connect your IDE to a remote app and trigger restart.

    • When NOT to use DevTools

    • In production — because it adds overhead and exposes detailed errors.
    • If you want full control over restarts (e.g., with external build tools or container-based deployments).

    • Summary Table

    • FeatureDescriptionDeveloper Benefit
      Hot SwappingReload changed classes without manual restartFaster dev cycle, instant feedback
      Auto RestartAutomatically restarts on code/resource changesSaves time, no manual restarts
      LiveReloadAuto refresh browser on resource changesNo manual refresh needed, better front-end dev
      Error PagesDetailed stack trace with source in browserEasier debugging and faster issue identification

       

      9️⃣ Spring Boot Logging — Detailed Explanation


      1. Default Logging in Spring Boot

      • Spring Boot uses Logback as the default logging framework.
      • When you create a Spring Boot project, Logback is included automatically (through spring-boot-starter).
      • You do not need to configure anything to start logging; it’s ready out of the box.
      • Log output:
        Logs are printed to the console by default with a default pattern including timestamps, log levels, thread, and message.

      2. Logging Levels

      Logging levels define the severity and verbosity of logs. The levels in increasing order of severity are:

      LevelDescriptionWhen to use
      TRACEMost detailed, logs everything including fine-grained events.Debugging very detailed issues
      DEBUGLess detailed than TRACE, used for debugging.Debugging logic flow and state changes
      INFOGeneral application info like startup, shutdown, major eventsProduction useful info, app lifecycle
      WARNPotential problems or important noticesWarnings that don’t stop app but should be noticed
      ERRORSerious issues like exceptionsErrors that might cause failure
      OFFTurns off loggingDisable logging

       

       

      How to set logging level?

      You can configure logging level globally or per package/class using application.properties or application.yml.

      Example: application.properties

       

      # Global logging level
      logging.level.root=INFO

      # Package specific level
      logging.level.com.sogdo.banking=DEBUG

      # Set SQL logging to TRACE (very verbose)
      logging.level.org.hibernate.SQL=TRACE
       

       

      3. External Logging Configuration

      • Spring Boot allows you to use your own Logback, Log4j2, or Java Util Logging configuration file instead of the default.
      • Place your config file under src/main/resources:
      FrameworkConfig file name
      Logbacklogback-spring.xml or logback.xml
      Log4j2log4j2-spring.xml or log4j2.xml
      Java Util Logginglogging.properties

       

      4. Logback Customization Example (Banking App)

      Create logback-spring.xml

      5. Logging in Code

      Use org.slf4j.Logger to log in your classes.

      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;

      @Service
      public class BankStatementService {

         private static final Logger logger = LoggerFactory.getLogger(BankStatementService.class);

         public List<Transaction> getTransactions(Long userId) {
             logger.info("Fetching transactions for userId: {}", userId);
             try {
                 // logic to fetch transactions
                 logger.debug("Querying database for transactions");
                 // ...
             } catch (Exception e) {
                 logger.error("Error fetching transactions", e);
             }
             return List.of(); // example
         }
      }
       

       

      6. Best Practices for Logging

      • Use appropriate log levels to avoid noisy logs in production.
      • Use parameterized logging (logger.info("User {} logged in", userId)) to avoid unnecessary string concatenation.
      • Avoid logging sensitive info like passwords or credit card numbers.
      • Use structured logging (JSON logs) if your infrastructure supports it for better log analysis.
      • Use external log management tools (like ELK stack, Splunk) to aggregate and analyze logs.

      Summary Table

      ConceptDescriptionExample Use Case
      Default LoggingUses Logback out of the boxConsole logs with timestamp and level
      Logging LevelsTRACE, DEBUG, INFO, WARN, ERRORDEBUG for dev, INFO for production
      External ConfigCustom logback-spring.xml to tailor loggingDifferent logging pattern per environment
      Logger APIUse SLF4J Logger for logging in classeslogger.info("User login: {}", userId)

       

       

      🔟 Spring Boot with REST (Core Concepts)


      1. @RestController and HTTP Method Annotations

      • @RestController = @Controller + @ResponseBody
        It means this controller handles REST APIs and returns the response body directly (usually JSON/XML) instead of resolving to a view.
      • HTTP method annotations define the endpoint type:
        • @GetMapping – For GET requests
        • @PostMapping – For POST requests
        • @PutMapping – For PUT requests
        • @DeleteMapping – For DELETE requests

      Example:

      @RestController
      @RequestMapping("/api/banking")
      public class TransactionController {

         @GetMapping("/transactions")
         public List<Transaction> getAllTransactions() {
             // Return all transactions (JSON response by default)
             return transactionService.getAll();
         }
         
         @PostMapping("/transaction")
         public Transaction createTransaction(@RequestBody Transaction transaction) {
             // Accept JSON request body, create and return transaction
             return transactionService.save(transaction);
         }
      }
       

      2. REST vs MVC (Model-View-Controller)

      AspectREST ControllerMVC Controller
      PurposeExpose RESTful APIs, return data (JSON/XML)Return Views (HTML pages, JSP, Thymeleaf)
      Annotation@RestController@Controller
      Response TypeJSON/XML typicallyHTML View templates
      Example Use CaseMobile apps, SPA frontend consuming JSONServer-side rendered web pages

       

      3. Returning JSON or XML

      • Spring Boot uses Jackson library by default for JSON serialization/deserialization.
      • To support XML, add dependency spring-boot-starter-xml (which brings JAXB or Jackson-dataformat-xml).
      • The response format depends on Accept HTTP header sent by the client.

      Example returning JSON or XML:

      @GetMapping(value = "/transaction/{id}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
      public Transaction getTransaction(@PathVariable Long id) {
         return transactionService.findById(id);
      }
       

      • If client sends Accept: application/json, response will be JSON.
      • If client sends Accept: application/xml, response will be XML.

      4. Handling RequestBody and Response

      • Use @RequestBody to map HTTP request body (JSON/XML) to Java object.
      • Use @ResponseBody (or @RestController) to automatically convert Java object to JSON/XML response.
      • You can return Java objects or ResponseEntity<T> for more control over HTTP status and headers.

      Example:

      @PostMapping("/transaction")
      public ResponseEntity<Transaction> createTransaction(@RequestBody Transaction transaction) {
         Transaction savedTransaction = transactionService.save(transaction);
         return ResponseEntity.status(HttpStatus.CREATED).body(savedTransaction);
      }
       

       

      5. Banking Example: Fetching Bank Statement

      Imagine you want to provide APIs for users to fetch bank statements by:

      • Current month
      • Specific month
      • Date range

      Controller:

      @RestController
      @RequestMapping("/api/banking/statements")
      public class BankStatementController {

         @Autowired
         private BankStatementService statementService;

         // 1. Current month statements
         @GetMapping("/current-month/{userId}")
         public List<Transaction> getCurrentMonthStatement(@PathVariable Long userId) {
             return statementService.getTransactionsForCurrentMonth(userId);
         }

         // 2. Specific month (year and month as params)
         @GetMapping("/month/{userId}")
         public List<Transaction> getStatementForMonth(
             @PathVariable Long userId,
             @RequestParam int year,
             @RequestParam int month) {
             return statementService.getTransactionsForMonth(userId, year, month);
         }

         // 3. Date range (startDate and endDate as query params)
         @GetMapping("/range/{userId}")
         public List<Transaction> getStatementForDateRange(
             @PathVariable Long userId,
             @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
             @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
             return statementService.getTransactionsForDateRange(userId, startDate, endDate);
         }
      }
       

       

      Explanation:

      • @PathVariable — Used for dynamic parts of URL path, e.g., userId.
      • @RequestParam — Used to pass query parameters, e.g., year, month, dates.
      • @DateTimeFormat — Ensures dates in query params are parsed properly.

       

      Summary Table of Key Annotations

      AnnotationPurposeExample
      @RestControllerMarks class as REST controller (returns response body)@RestController
      @GetMappingMaps GET HTTP requests@GetMapping("/transactions")
      @PostMappingMaps POST HTTP requests@PostMapping("/transaction")
      @RequestBodyBinds HTTP request body (JSON/XML) to Java objectpublic void save(@RequestBody Transaction txn)
      @ResponseBodyReturns Java object as response bodyUsually implicit in @RestController
      @PathVariableExtracts variable from URI path/user/{id}, @PathVariable Long id
      @RequestParamExtracts query parameters from URL/transactions?year=2024&month=5

       

       

       

      1️⃣1️⃣ Spring Boot Error Handling


      1. Default Error Handling in Spring Boot

      • Spring Boot provides a default error page for any uncaught exceptions or HTTP errors.
      • This default error page is a whitelabel error page — a simple HTML page showing status code and error message.
      • It’s powered by Spring Boot’s BasicErrorController (which implements ErrorController interface).

      Example: When a request hits an unknown URL or an exception is thrown, you get a default page like:

      Whitelabel Error Page
      This application has no explicit mapping for /error, so you are seeing this as a fallback.
      There was an unexpected error (type=Not Found, status=404).
      No message available
      

       

      2. ErrorController Interface

      • Spring Boot uses ErrorController to map /error path to error handling logic.
      • You can implement your own ErrorController to override default behavior for all errors globally.

      Example:

      @Controller
      public class CustomErrorController implements ErrorController {

         @RequestMapping("/error")
         public String handleError(HttpServletRequest request) {
             // You can retrieve error status and details from request attributes
             Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
             Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
             
             // Return your own error view name
             return "customErrorPage";
         }

         @Override
         public String getErrorPath() {
             return "/error";
         }
      }
       

      3. Custom Error Pages (HTML / JSON)

      • You can customize error responses for HTML or REST APIs by creating your own error pages or JSON responses.

      For HTML:

      • Create error pages in src/main/resources/templates/error/ named by HTTP status codes:

       

      error/404.html
      error/500.html
      error/default.html
       

      Spring Boot will automatically pick these pages for the respective errors.

      For JSON (REST API):

      • Override error response by creating a @ControllerAdvice or @RestControllerAdvice with @ExceptionHandler.

      4. @ControllerAdvice (Core to Spring Boot Error Handling)

      • It’s a global exception handler for controllers.
      • Use it to handle exceptions across all controllers and return custom JSON or views.
      • Supports handling specific exceptions or all exceptions.

      Example: Banking API global error handler

      @RestControllerAdvice
      public class GlobalExceptionHandler {

         @ExceptionHandler(TransactionNotFoundException.class)
         public ResponseEntity<ErrorResponse> handleTransactionNotFound(TransactionNotFoundException ex) {
             ErrorResponse error = new ErrorResponse(HttpStatus.NOT_FOUND.value(),
                                                     ex.getMessage(),
                                                     System.currentTimeMillis());
             return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
         }

         @ExceptionHandler(Exception.class)
         public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
             ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                                                     "Something went wrong. Please try again.",
                                                     System.currentTimeMillis());
             return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
         }
      }
       

       

      Explanation:

      • @RestControllerAdvice acts globally.
      • @ExceptionHandler specifies exception type to handle.
      • Returning custom error response with status and message.

      ErrorResponse DTO:

      public class ErrorResponse {
         private int status;
         private String message;
         private long timeStamp;

         // constructors, getters, setters
      }
       

       

       

      1️⃣2️⃣ Spring Boot Actuator


      1. Introduction to Actuator

      • Spring Boot Actuator provides production-ready features to monitor and manage your Spring Boot application.
      • It exposes endpoints over HTTP or JMX to provide info about application health, metrics, environment, etc.
      • Helps developers & ops teams monitor, troubleshoot, and gain insights without custom coding.

      Why use Actuator?

      • Easy monitoring of app health
      • Track metrics (requests, CPU, memory)
      • View configuration properties & environment
      • Trace HTTP requests
      • Audit app events and much more

      2. How to Add Actuator

      Add the dependency in pom.xml:

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

      3. Common Actuator Endpoints

      By default, some endpoints are enabled (like /actuator/health, /actuator/info), others are disabled or restricted.

      EndpointDescriptionDefault Exposure
      /actuator/healthShows app health statusPublic
      /actuator/infoCustom application infoPublic
      /actuator/metricsMetrics like memory, CPU, etc.Restricted
      /actuator/httptraceRecent HTTP requestsRestricted
      /actuator/envEnvironment propertiesRestricted

       

      4. Health Check & Metrics

      Health Check

      • The /actuator/health endpoint gives you the health status of the app: UP, DOWN, OUT_OF_SERVICE, or UNKNOWN.
      • You can add custom health indicators to report health of dependencies like databases or external services.

      Example: Custom health check for banking database connection

      @Component
      public class BankDbHealthIndicator implements HealthIndicator {

         @Override
         public Health health() {
             // Check if bank database is reachable
             boolean dbUp = checkDatabaseConnection(); // your logic here

             if (dbUp) {
                 return Health.up().withDetail("Bank DB", "Available").build();
             } else {
                 return Health.down().withDetail("Bank DB", "Not reachable").build();
             }
         }

         private boolean checkDatabaseConnection() {
             // Implementation: ping DB or query a simple select 1
             return true; // assuming OK here
         }
      }
       

       

      Metrics

      • The /actuator/metrics endpoint exposes key performance metrics.
      • You can query metrics by name, e.g. /actuator/metrics/jvm.memory.used.

      5. Custom Endpoints

      You can create your own actuator endpoints to expose custom info or operations.

      Example: Custom banking actuator endpoint to show number of transactions today

      @Component
      @Endpoint(id = "transactionCount")
      public class TransactionCountEndpoint {

         private final TransactionService transactionService;

         public TransactionCountEndpoint(TransactionService transactionService) {
             this.transactionService = transactionService;
         }

         @ReadOperation
         public int transactionsToday() {
             return transactionService.countTransactionsForToday();
         }
      }
       

      @Component
      @Endpoint(id = "transactionCount")
      public class TransactionCountEndpoint {

         private final TransactionService transactionService;

         public TransactionCountEndpoint(TransactionService transactionService) {
             this.transactionService = transactionService;
         }

         @ReadOperation
         public int transactionsToday() {
             return transactionService.countTransactionsForToday();
         }
      }
       

      • Exposed at /actuator/transactionCount
      • You can add @WriteOperation or @DeleteOperation for other REST verbs.

      6. Securing Actuator Endpoints (Minimal)

      By default, sensitive actuator endpoints like /metrics and /env are not exposed publicly.

      Enable all endpoints in application.properties:

       

      management.endpoints.web.exposure.include=health,info,metrics,env,transactionCount
       

       

      Minimal security example:

      @Configuration
      public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {

         @Override
         protected void configure(HttpSecurity http) throws Exception {
             http
                 .authorizeRequests()
                 .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR_ADMIN")
                 .and()
                 .httpBasic();
         }
      }
       

       

      • This requires users to have role ACTUATOR_ADMIN to access actuator endpoints.
      • Configure user in application.properties or via other security mechanisms.

       

       

      Next→

       

      1️⃣3️⃣ Spring Boot Testing (Core Concepts)

      Spring Boot provides powerful testing support to validate layers (controller, service, repository) with minimal configuration using special annotations called Test Slices.


      🔹 @SpringBootTest

      • Loads the full application context (like production).
      • Best for integration tests across all layers.

      @SpringBootTest
      public class BankingIntegrationTest {

         @Autowired
         private TransactionService transactionService;

         @Test
         void testMonthlyStatementFetch() {
             List<Transaction> list = transactionService.getTransactionsByMonth("2024-12");
             assertEquals(10, list.size());
         }
      }
       

      🔧 Use when: Testing multiple beans (controller + service + repo + config)

       

       

      🔹 @WebMvcTest

      • Loads only Controller layer + minimal web config.
      • No @Service, @Repository loaded unless manually mocked.

       

      @WebMvcTest(TransactionController.class)
      public class TransactionControllerTest {

         @Autowired
         private MockMvc mockMvc;

         @MockBean
         private TransactionService transactionService;

         @Test
         void testGetCurrentMonthTransactions() throws Exception {
             when(transactionService.getCurrentMonthTransactions()).thenReturn(mockedList());

             mockMvc.perform(get("/transactions/current-month"))
                    .andExpect(status().isOk());
         }
      }
       

       

      🔧 Use when: You want to test only Controller + Request/Response mapping.

       

      🔹 @DataJpaTest

      Loads only JPA repository and DB layer (uses embedded H2 by default).

      Useful for DB query testing without loading full app.

      @DataJpaTest
      public class TransactionRepositoryTest {

         @Autowired
         private TransactionRepository transactionRepo;

         @Test
         void testFindByMonth() {
             transactionRepo.save(new Transaction(...));
             List<Transaction> result = transactionRepo.findByMonth("2025-01");
             assertFalse(result.isEmpty());
         }
      }
       

      🔧 Use when: Testing DB logic in isolation.

      🔹 ApplicationContext loading

      • Use @ContextConfiguration to load custom context in special cases.
      • Default behavior in Spring Boot is to auto-detect main config class.

       

       

      1️⃣4️⃣ Spring Boot Deployment

      🔹 Creating JAR/WAR

      By default, Spring Boot builds fat JAR with embedded server.

      In pom.xml:

       

      <build>
       <plugins>
         <plugin>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
       </plugins>
      </build>
       

      To build:

      mvn clean package
       

      To run:

      java -jar target/banking-app-1.0.jar
       

      🔹 WAR Deployment

      If deploying to external Tomcat server (rare today):

      • Set packaging to war
      • Extend SpringBootServletInitializer
      • Provide configure() method

       

       

      🔹 External Config on Deployment

      Spring Boot supports overriding config without rebuilding the app:

      java -jar banking-app.jar --spring.config.location=/opt/config/
       

       

      or via env variables:

       

      SPRING_DATASOURCE_URL=jdbc:mysql://... java -jar ...
       

       

      🔹 Embedded Servers

      Spring Boot supports:

      ServerDependency
      Tomcat (default)spring-boot-starter-web
      Jettyspring-boot-starter-jetty
      Undertowspring-boot-starter-undertow

       

      To switch:

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-jetty</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <scope>provided</scope> <!-- disables embedded tomcat -->
      </dependency>
       

       

      1️⃣5️⃣ Spring Boot Application Lifecycle

      🔹 CommandLineRunner & ApplicationRunner

      Used to execute logic at startup.

      Use-case: Initializing DB or caching configs

       

      @Component
      public class StartupRunner implements CommandLineRunner {
         @Override
         public void run(String... args) {
             System.out.println("Initializing core banking APIs...");
         }
      }
       

      @Component
      public class StartupRunner implements CommandLineRunner {
         @Override
         public void run(String... args) {
             System.out.println("Initializing core banking APIs...");
         }
      }
       

      ApplicationRunner is similar, but provides ApplicationArguments.

      🔹 Graceful Shutdown

      Spring Boot (2.3+) handles graceful shutdown using:

      server.shutdown=graceful
      spring.lifecycle.timeout-per-shutdown-phase=30s


      You can hook into shutdown:

      @PreDestroy
      public void onDestroy() {
         // cleanup banking transactions or close DBs
      }

      SPring Banners last topic you can do it own.

      end → Please support our work on https://razorpay.me/@niteshsynergy

       

52 min read
May 20, 2025
By Nitesh Synergy
Share

Leave a comment

Your email address will not be published. Required fields are marked *