A production-ready example of Spring Boot project using N-layered architecture.
Layers are virtual separations within an application that organize its different parts, such as the presentation layer (UI), the business logic layer, and the data access layer.
It contains several variations of a Spring Boot application layered by:
- technology - the most commonly used approach
- feature - focuses on features not on a technology separation
- module - using modules for different features
The project is still in very early phase and doesn't represent the final vision!
Java and Maven are managed by SDKMAN. To install the defined versions in .sdkmanrc
file run the command:
sdk env install
- Local Development & Testing - the database is managed by Docker-compose
- CI/CD - the database is managed by the CI/CD system
Database changes are tracked and executed using a third-party tool - Flyway or Liquibase. Each of these tools is able to manage database migrations, so you don't have to implement an in-house solution.
Spring Boot native integrations of Docker-compose and Liquibase are responsible to initialize the DB (defined as part of the docker-compose.yaml file(add link to the file)) and run the specified migrations. The DB will not be stopped as part of the application shutdown in order to allow faster development cycles.
Same as development, but DB is stopped, so we have fresh DB on every test run.
It's assumed that DB is already up&running, so Docker-compose is disabled. Spring Boot Liquibase native integration runs the specified migrations.
The general concept is to execute the migrations before the application initialization when deploying the service in the cloud. A Docker image is created as part of each build when code is merged to corresponding branch by copying the specified migrations in the image. Then the image is executed against a specific database server and migrations are applied. Only when the database migration is successful, then we move to application deployment.
Running database migrations on application startup is not recommended because:
- The startup is slower to the point where schedulers like Kubernetes may kill them (pay attention to liveness vs. readiness probes)
- The application must run on a more privileged DB user supporting schema updates
- Other instances may be blocked until the first one completes migrations
- If you don't have redundancy, you get downtime during migration
That being said, consider running migration automatically prior to deployment
Database migrations are defined in their default place depending on the selected tool (add links to the folders)
- Local build
docker build -t liquibase-migrations:latest -f docker/db-migrations/Dockerfile.liquibase .
- CI/CD Build
docker build -t liquibase-migrations:<desired_tag> -f docker/db-migrations/Dockerfile.liquibase .
- Local
docker run --network=database -e DB_USERNAME=postgres -e DB_PASSWORD=password -e DB_URL=jdbc:postgresql://db:5432/spring_boot_nlayered_service liquibase-migrations:latest
- CI/CD
docker run -e DB_USERNAME=<env_db_username> -e DB_PASSWORD=<env_db_password> -e
DB_URL=jdbc:postgresql://<env_db_host>:<env_db_port>/spring_boot_nlayered_service
liquibase-migrations:<docker_repo_tag>
by replacing the variables wrapped in <>