GitHub - raeperd/realworld-springboot-java: Spring boot java implementation of realworld example.app
ReadWorld.io backend project using spring boot java using spring-security, spring-data-jpa
Insprired by
- 우아한형제들 기술 불로그 | Todo list 만들기는 이제 그만
- 우아한형제들 기술 블로그 | Gradle 프로젝트에 JaCoCo 설정하기
- 우아한형제들 기술 블로그 | 우린 Git-flow를 사용하고 있어요
- Github | Realworld.io
Getting started
Build from scratch
$ ./gradlew build bootRun
Using docker
$ docker run --rm -p 8080:8080 ghcr.io/raeperd/realworld-spring-boot-java:main
- Dockerhub registry is here
- Container tags are simply branch name of this repository following git-flow strategy
How to test
After run application, you can try one of followings
using shell script
using postman
Import ./doc/Conduit.postman_collection.json in your postman application
And also, pure gradle test covers almost every line of code.
More details can be found in ./doc/README.md and original source
Overview
Design Principal
- Always
finalwhenever possible - Always package private class whenever possible
- Always test every package, class, method, instruction in codes
- Except for some boilerplate
equalsandhashcodemethod - This is validated by jacoco-gradle-plugin.
- Coverage verification in
./test.gradle
- Except for some boilerplate
- Try to avoid including additional dependencies as much as possible
- Implements JWT generation / validation logic without 3rd party library #3
- Try to maintain codes in domain package remain POJO
- Except for special spring annotations like
@Service,@Repository,@Transactional - Prohibit use of lombok in domain package
- Except for special spring annotations like
- Try to follow all modern best practices for spring-boot project
Diagrams
- You can open full diagram file in
realworld.drawiousing draw.io
User
- Separate password encoding logic out of User.
- User must be created with password encoder.
Article
- Article contains other elements with
@Embeddedclasses - Try to reduce number of repositories.
- Prefer
@JoinTableto@JoinColumn
JWT
- Try not to use 3rd party library
- Serialization and Deserialization are seperated with interfaces
- Domain package contains interface, infrastructure code provide implementation
- Application package do stuff with spring-security logic
Performance
Result of ./doc/run-api-tests.sh, run 100 times for each version.
| Version | Runs | Requests | Failures | Avg response time | P50 | P90 | P95 | P99 | Max | Avg full run duration |
|---|---|---|---|---|---|---|---|---|---|---|
Before Spring Boot 4 upgrade (d9c19f1) |
100 | 3100 | 0 | 21.64ms | 6.0ms | 113ms | 123ms | 137ms | 188ms | 16.848s |
After Spring Boot 4 upgrade (18432fa) |
100 | 3100 | 0 | 21.10ms | 6.0ms | 115ms | 119ms | 131ms | 233ms | 16.866s |
| Java 25 with virtual threads | 100 | 3100 | 0 | 20.31ms | 6.0ms | 104ms | 116ms | 128ms | 210ms | 16.765s |
Java 25 with virtual threads is not meaningfully slower than the Java 17 baseline. Average response time and tail latency were slightly better in this local run.
What can be done more
- User class doing so many things now. It can be improved someway.
- Service classes can be divided into smaller services
- Test cases order can be improved
Contact
You can contact me with email or issue in this project



