Building BBank Architecture with Spring Cloud, Gateway & Eureka

Note: This tutorial implements the architecture shown in We'll create 5 microservices: Eureka Server, API Gateway, Account Service, Customer Service, and Transaction Service.
BBank Microservices Architecture

📁 Project Structure

  • eureka-server - Service registry
  • api-gateway - Entry point for all requests
  • account-service - Manages bank accounts
  • customer-service - Manages customer information
  • transaction-service - Handles money transfers between accounts

Step 1: Create Eureka Server

The Eureka Server acts as a service registry where all microservices register themselves.

📁 File: eureka-server/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
    </parent>

    <groupId>com.bbank</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka-server</name>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

📁 File: eureka-server/src/main/resources/application.yml

server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
  server:
    enable-self-preservation: false

📁 File: eureka-server/src/main/java/com/bbank/eurekaserver/EurekaServerApplication.java

package com.bbank.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

Step 2: Create API Gateway

The API Gateway routes requests to appropriate microservices and provides a single entry point.

📁 File: api-gateway/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
    </parent>

    <groupId>com.bbank</groupId>
    <artifactId>api-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>api-gateway</name>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

📁 File: api-gateway/src/main/resources/application.yml

server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: account-service
          uri: lb://account-service
          predicates:
            - Path=/api/accounts/**
        - id: customer-service
          uri: lb://customer-service
          predicates:
            - Path=/api/customers/**
        - id: transaction-service
          uri: lb://transaction-service
          predicates:
            - Path=/api/transactions/**

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
    fetch-registry: true
    register-with-eureka: true

📁 File: api-gateway/src/main/java/com/bbank/apigateway/ApiGatewayApplication.java

package com.bbank.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

Step 3: Create Account Service

This service manages bank accounts and their balances.

📁 File: account-service/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
    </parent>

    <groupId>com.bbank</groupId>
    <artifactId>account-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>account-service</name>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

📁 File: account-service/src/main/resources/application.yml

server:
  port: 8081

spring:
  application:
    name: account-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

📁 File: account-service/src/main/java/com/bbank/accountservice/model/Account.java

package com.bbank.accountservice.model;

public class Account {
    private Long id;
    private Long customerId;
    private String accountNumber;
    private Double balance;

    // Constructors
    public Account() {}
    public Account(Long id, Long customerId, String accountNumber, Double balance) {
        this.id = id;
        this.customerId = customerId;
        this.accountNumber = accountNumber;
        this.balance = balance;
    }

    // Getters and Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public Long getCustomerId() { return customerId; }
    public void setCustomerId(Long customerId) { this.customerId = customerId; }
    public String getAccountNumber() { return accountNumber; }
    public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; }
    public Double getBalance() { return balance; }
    public void setBalance(Double balance) { this.balance = balance; }
}

📁 File: account-service/src/main/java/com/bbank/accountservice/repository/AccountRepository.java

package com.bbank.accountservice.repository;

import com.bbank.accountservice.model.Account;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Repository
public class AccountRepository {
    private final ConcurrentHashMap<Long, Account> accounts = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong(1);

    public Account save(Account account) {
        if (account.getId() == null) {
            account.setId(idGenerator.getAndIncrement());
        }
        accounts.put(account.getId(), account);
        return account;
    }

    public Account findById(Long id) {
        return accounts.get(id);
    }

    public List<Account> findByCustomerId(Long customerId) {
        return accounts.values().stream()
                .filter(acc -> acc.getCustomerId().equals(customerId))
                .toList();
    }

    public List<Account> findAll() {
        return new ArrayList<>(accounts.values());
    }

    public boolean updateBalance(Long id, Double newBalance) {
        Account account = accounts.get(id);
        if (account != null) {
            account.setBalance(newBalance);
            return true;
        }
        return false;
    }
}

📁 File: account-service/src/main/java/com/bbank/accountservice/controller/AccountController.java

package com.bbank.accountservice.controller;

import com.bbank.accountservice.model.Account;
import com.bbank.accountservice.repository.AccountRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/accounts")
public class AccountController {

    @Autowired
    private AccountRepository accountRepository;

    @GetMapping
    public List<Account> getAllAccounts() {
        return accountRepository.findAll();
    }

    @GetMapping("/{id}")
    public Account getAccountById(@PathVariable Long id) {
        return accountRepository.findById(id);
    }

    @GetMapping("/customer/{customerId}")
    public List<Account> getAccountsByCustomerId(@PathVariable Long customerId) {
        return accountRepository.findByCustomerId(customerId);
    }

    @PostMapping
    public Account createAccount(@RequestBody Account account) {
        return accountRepository.save(account);
    }

    @PutMapping("/{id}/balance")
    public boolean updateBalance(@PathVariable Long id, @RequestBody Double newBalance) {
        return accountRepository.updateBalance(id, newBalance);
    }
}

📁 File: account-service/src/main/java/com/bbank/accountservice/AccountServiceApplication.java

package com.bbank.accountservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

Step 4: Create Customer Service

This service manages customer information.

📁 File: customer-service/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
    </parent>

    <groupId>com.bbank</groupId>
    <artifactId>customer-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>customer-service</name>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

📁 File: customer-service/src/main/resources/application.yml

server:
  port: 8082

spring:
  application:
    name: customer-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

📁 File: customer-service/src/main/java/com/bbank/customerservice/model/Customer.java

package com.bbank.customerservice.model;

public class Customer {
    private Long id;
    private String name;
    private String email;
    private String phone;

    public Customer() {}
    public Customer(Long id, String name, String email, String phone) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.phone = phone;
    }

    // Getters and Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
}

📁 File: customer-service/src/main/java/com/bbank/customerservice/repository/CustomerRepository.java

package com.bbank.customerservice.repository;

import com.bbank.customerservice.model.Customer;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Repository
public class CustomerRepository {
    private final ConcurrentHashMap<Long, Customer> customers = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong(1);

    public Customer save(Customer customer) {
        if (customer.getId() == null) {
            customer.setId(idGenerator.getAndIncrement());
        }
        customers.put(customer.getId(), customer);
        return customer;
    }

    public Customer findById(Long id) {
        return customers.get(id);
    }

    public List<Customer> findAll() {
        return new ArrayList<>(customers.values());
    }
}

📁 File: customer-service/src/main/java/com/bbank/customerservice/controller/CustomerController.java

package com.bbank.customerservice.controller;

import com.bbank.customerservice.model.Customer;
import com.bbank.customerservice.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/customers")
public class CustomerController {

    @Autowired
    private CustomerRepository customerRepository;

    @GetMapping
    public List<Customer> getAllCustomers() {
        return customerRepository.findAll();
    }

    @GetMapping("/{id}")
    public Customer getCustomerById(@PathVariable Long id) {
        return customerRepository.findById(id);
    }

    @PostMapping
    public Customer createCustomer(@RequestBody Customer customer) {
        return customerRepository.save(customer);
    }
}

📁 File: customer-service/src/main/java/com/bbank/customerservice/CustomerServiceApplication.java

package com.bbank.customerservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

Step 5: Create Transaction Service

This service handles money transfers between accounts using Feign clients to communicate with Account Service.

📁 File: transaction-service/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
    </parent>

    <groupId>com.bbank</groupId>
    <artifactId>transaction-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>transaction-service</name>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

📁 File: transaction-service/src/main/resources/application.yml

server:
  port: 8083

spring:
  application:
    name: transaction-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

📁 File: transaction-service/src/main/java/com/bbank/transactionservice/model/Transaction.java

package com.bbank.transactionservice.model;

public class Transaction {
    private Long id;
    private Long fromAccountId;
    private Long toAccountId;
    private Double amount;
    private String status; // e.g., "SUCCESS", "FAILED"

    public Transaction() {}
    public Transaction(Long id, Long fromAccountId, Long toAccountId, Double amount, String status) {
        this.id = id;
        this.fromAccountId = fromAccountId;
        this.toAccountId = toAccountId;
        this.amount = amount;
        this.status = status;
    }

    // Getters and Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public Long getFromAccountId() { return fromAccountId; }
    public void setFromAccountId(Long fromAccountId) { this.fromAccountId = fromAccountId; }
    public Long getToAccountId() { return toAccountId; }
    public void setToAccountId(Long toAccountId) { this.toAccountId = toAccountId; }
    public Double getAmount() { return amount; }
    public void setAmount(Double amount) { this.amount = amount; }
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
}

📁 File: transaction-service/src/main/java/com/bbank/transactionservice/client/AccountServiceClient.java

package com.bbank.transactionservice.client;

import com.bbank.transactionservice.model.Account;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "account-service")
public interface AccountServiceClient {

    @GetMapping("/api/accounts/{id}")
    Account getAccount(@PathVariable("id") Long id);

    @PutMapping("/api/accounts/{id}/balance")
    Boolean updateBalance(@PathVariable("id") Long id, @RequestBody Double newBalance);
}

📁 File: transaction-service/src/main/java/com/bbank/transactionservice/repository/TransactionRepository.java

package com.bbank.transactionservice.repository;

import com.bbank.transactionservice.model.Transaction;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Repository
public class TransactionRepository {
    private final ConcurrentHashMap<Long, Transaction> transactions = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong(1);

    public Transaction save(Transaction transaction) {
        if (transaction.getId() == null) {
            transaction.setId(idGenerator.getAndIncrement());
        }
        transactions.put(transaction.getId(), transaction);
        return transaction;
    }

    public List<Transaction> findAll() {
        return new ArrayList<>(transactions.values());
    }

    public List<Transaction> findByAccountId(Long accountId) {
        return transactions.values().stream()
                .filter(t -> t.getFromAccountId().equals(accountId) || t.getToAccountId().equals(accountId))
                .toList();
    }
}

📁 File: transaction-service/src/main/java/com/bbank/transactionservice/service/TransactionService.java

package com.bbank.transactionservice.service;

import com.bbank.transactionservice.client.AccountServiceClient;
import com.bbank.transactionservice.model.Account;
import com.bbank.transactionservice.model.Transaction;
import com.bbank.transactionservice.repository.TransactionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TransactionService {

    @Autowired
    private AccountServiceClient accountServiceClient;

    @Autowired
    private TransactionRepository transactionRepository;

    public Transaction transferMoney(Long fromAccountId, Long toAccountId, Double amount) {
        Account fromAccount = accountServiceClient.getAccount(fromAccountId);
        Account toAccount = accountServiceClient.getAccount(toAccountId);

        if (fromAccount == null || toAccount == null) {
            return new Transaction(null, fromAccountId, toAccountId, amount, "FAILED - Account not found");
        }

        if (fromAccount.getBalance() < amount) {
            return new Transaction(null, fromAccountId, toAccountId, amount, "FAILED - Insufficient balance");
        }

        // Deduct from sender
        boolean fromUpdated = accountServiceClient.updateBalance(fromAccountId, fromAccount.getBalance() - amount);
        if (!fromUpdated) {
            return new Transaction(null, fromAccountId, toAccountId, amount, "FAILED - Could not update sender balance");
        }

        // Add to receiver
        boolean toUpdated = accountServiceClient.updateBalance(toAccountId, toAccount.getBalance() + amount);
        if (!toUpdated) {
            // Rollback sender
            accountServiceClient.updateBalance(fromAccountId, fromAccount.getBalance());
            return new Transaction(null, fromAccountId, toAccountId, amount, "FAILED - Could not update receiver balance");
        }

        Transaction transaction = new Transaction();
        transaction.setFromAccountId(fromAccountId);
        transaction.setToAccountId(toAccountId);
        transaction.setAmount(amount);
        transaction.setStatus("SUCCESS");

        return transactionRepository.save(transaction);
    }

    public Iterable<Transaction> getAllTransactions() {
        return transactionRepository.findAll();
    }

    public Iterable<Transaction> getTransactionsByAccountId(Long accountId) {
        return transactionRepository.findByAccountId(accountId);
    }
}

📁 File: transaction-service/src/main/java/com/bbank/transactionservice/controller/TransactionController.java

package com.bbank.transactionservice.controller;

import com.bbank.transactionservice.model.Transaction;
import com.bbank.transactionservice.service.TransactionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

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

    @Autowired
    private TransactionService transactionService;

    @PostMapping("/transfer")
    public Transaction transferMoney(@RequestParam Long fromAccountId,
                                     @RequestParam Long toAccountId,
                                     @RequestParam Double amount) {
        return transactionService.transferMoney(fromAccountId, toAccountId, amount);
    }

    @GetMapping
    public Iterable<Transaction> getAllTransactions() {
        return transactionService.getAllTransactions();
    }

    @GetMapping("/account/{accountId}")
    public Iterable<Transaction> getTransactionsByAccountId(@PathVariable Long accountId) {
        return transactionService.getTransactionsByAccountId(accountId);
    }
}

📁 File: transaction-service/src/main/java/com/bbank/transactionservice/TransactionServiceApplication.java

package com.bbank.transactionservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

✅ Final Step: Run All Services

Start services in this order:

  1. Eureka Server → http://localhost:8761
  2. Account Service
  3. Customer Service
  4. Transaction Service
  5. API Gateway → http://localhost:8080

🧪 Test Endpoints via Gateway

  • Get all accounts: GET http://localhost:8080/api/accounts
  • Create customer: POST http://localhost:8080/api/customers
  • Transfer money: POST http://localhost:8080/api/transactions/transfer?fromAccountId=1&toAccountId=2&amount=100
🎉 Congratulations! You now have a fully working Spring Cloud Microservices system with:
  • Service Discovery (Eureka)
  • API Gateway (Spring Cloud Gateway)
  • Inter-service communication (Feign Client)
  • REST APIs for Account, Customer, Transaction
© 2025 Spring Boot Microservices Tutorial | BBank Architecture

Created for educational purposes. Extend with databases, security, Docker, etc.