- Table of Contents
- Project setup (non-Docker approach)
- Docker-based Setup
- Virtual threads
- Windows and Unix line separators
- IntelliJ plugins
This is a demo project using Spring Boot to work as a blog site's backend.
- JDK 21 or higher
- PostgreSQL (https://www.postgresql.org/download/) installed on your local machine.
- Because database changelogs use native PostgreSQL dialect, you will need to use PostgreSQL. If you planned to use another RDBMS, then you will have to rewrite the changelog files.
- Elasticsearch on port
9200and9300
If you use Docker (Windows), you can run one of the following batch files:
Run the following SQL Script to create a database with:
- name
myspringdatabase - username
myspringdatabase - password of
123456
CREATE ROLE myspringdatabase WITH
LOGIN
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
INHERIT
NOREPLICATION
CONNECTION LIMIT -1
PASSWORD '123456';
CREATE
DATABASE myspringdatabase
WITH
OWNER = myspringdatabase
ENCODING = 'UTF8'
CONNECTION LIMIT = -1
IS_TEMPLATE = False;Create a Run configuration based on liquibase:validate goal, using following command:
clean compile liquibase:validate -Dliquibase.changeLogFile=src/main/resources/changelog.yaml -Dliquibase.url=jdbc:postgresql://localhost:5432/myspringdatabase -Dliquibase.username=postgres -Dliquibase.password=123456 -f pom.xmlReplace -Dliquibase.username and -Dliquibase.password with your actual username and password.
For SPRING_PROFILES_ACTIVE, you can use development most of the time.
Spring Security uses these environment variables for authentication and authorization:
| Variable name | Description | Remarks |
|---|---|---|
PUBLIC_KEY |
The public key used to verify JWT Authorization | RSA public key (2048 bits or more) |
PRIVATE_KEY |
The private key used to generate access token for authenticated user | RSA private key (2048 bits or more) |
For security reasons, I will not include the key pair here, and you will have to define them.
For personal use, you can generate your own key pair using an online tool like: https://www.devglan.com/online-tools/rsa-encryption-decryption
To facilitate environment variables in IntelliJ (which you should use frequently), you can use the plugin EnvFile (https://plugins.jetbrains.com/plugin/7861-envfile) and enable the
.envfiles when editing run configuration.
A simple .env file looks like this
PUBLIC_KEY=insert your public key here
PRIVATE_KEY=insert your private key here
#
# Other environment variables down below
#You can check the example on .env-example file.
Currently, an RSA public or private key is written in a single line, for example:
PUBLIC_KEY=-----BEGIN PUBLIC KEY-----<single line here>-----END PUBLIC KEY-----PRIVATE_KEY=-----BEGIN PRIVATE KEY-----<single line here>-----END PRIVATE KEY-----Run the project using Docker:
docker compose upVerify at http://localhost:8443/health once containers are running.
This approach bypasses manual prerequisite installation.
With the arrival of Java 21 and Spring Boot 3.2 onwards, you can use virtual threads to overcome the limited number of platform threads managed by some sort of reactor library.
WORDS OF WARNING:
Test your application thoroughly, as the usage of virtual threads might break critical functions in your app. Use virtual threads with caution for older projects.
From Spring 3.2 onwards, all you need is this line in your application.properties file:
spring.thread.virtuals.enabled=trueYou will need to implement some workarounds to get the best from virtual threads if you are not using Spring Boot 3.2 ( but still using Java 21 and Spring Framework 6), like this:
import java.util.concurrent.Executors;
import org.apache.coyote.ProtocolHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@Configuration
@ConditionalOnProperty(prefix = "spring.threads", value = "virtual", havingValue = "true")
public class ThreadConfig {
@Bean
public AsyncTaskExecutor applicationTaskExecutor() {
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}
@Bean
public TomcatProtocolHandlerCustomizer<ProtocolHandler>
protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler ->
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
}Source: Baeldung
Make API call (without authorization) to
/free/tax-calculator?basicSalary=5100000&totalSalary=6100000
to verify that Virtual Thread is indeed in use (use console log!)
When using Windows, your mvnw file might have Windows-style CRLF line endings instead of Unix-style LF when
committing, which can cause image build failures. To fix this issue using PowerShell, run:
(Get-Content mvnw -Raw).Replace("`r`n", "`n") | Set-Content mvnw -NoNewline -ForceIn some cases, you may need to make the mvnw file executable by setting the +x permission attribute, like this:
git update-index --chmod=+x mvnwYou can use Windows Subsystem for Linux to achieve the same:
chmod +x mvnwYou might have mixed feelings about Google Java Format plugins, but I've found them very useful for catching those tricky-to-spot errors – especially when dealing with nested parentheses. If you're curious, I'd definitely recommend giving it a shot. Just head to the IntelliJ plugins menu, search for "Google Java Format," and you're all set.
Or here is the link:
https://plugins.jetbrains.com/plugin/8527-google-java-format
Other useful plugins I can recommend:
https://plugins.jetbrains.com/plugin/10036-mapstruct-support
You may hold it dear as if it God's gospel, or anything else I really can't care more.