Spring Framework / Spring Boot Projects
This page contains documentation and examples specific for Spring Framework and Spring Boot Projects.
General Information
The Spring Framework and Spring Boot are JVM Runtime frameworks. What this means is that they provide all their features at runtime.
The IoC container as the central core of the Spring Framework inspects the runtime environment at application startup.
For that it uses mainly the classpath of the JVM.
It collects all configurations, instantiates services and injects dependencies.
Configurations can come from various places like Java Properties files, YAML files or Java @Configuration classes.
The Spring Boot framework additionally scans the runtime classpath to auto-detect other frameworks and Spring Boot specific features. Based on it’s finding it enables dedicated features. Additionally, you can configure Spring Boot programmatically and via configuration files.
As a consequence, Spring projects typically don’t need any special support from a build tool, which is nice, since you don’t need to lean any new Mill-specific concepts when you want to use Mill for your Spring projects. Spring Boot is also not tied to use of Java. It is easily possible to use or mix different JVM languages in your Spring projects.
Being a runtime framework also means, that most issues you may encounter like configuration problems, missing dependencies, dependency conflicts or unexpected application behavior, can’t be easily detected at build-time. These often require inspection of the running or starting application and dealing with error messages and JVM stack traces. The use of a debugger can be sometimes necessary. When developing Spring projects, you should therefore also maintain a functional test suite.
Some tools provided by the Spring Boot project are also useful outside of Spring Boot projects, hence Mill makes them available even for non-Spring project. Those are linked below:
-
RepackageModule- Creates self-running application assemblies in a single-jar
Spring Boot Web with Initializr
package build
import mill.*
import mill.javalib.*
object `package` extends MavenModule {
def bomMvnDeps = Seq(
mvn"org.springframework.boot:spring-boot-dependencies:3.5.7"
)
def mvnDeps = Seq(mvn"org.springframework.boot:spring-boot-starter-web")
object test extends MavenTests, TestModule.Junit5 {
def bomMvnDeps = Seq(
mvn"org.springframework.boot:spring-boot-dependencies:3.5.7"
)
def mvnDeps =
Seq(mvn"org.springframework.boot:spring-boot-starter-test")
}
}
This example demonstrates how to configure mill for a simple initializr project, using https://start.spring.io/ by choosing:
-
Project: maven
-
Language: Java
-
Dependencies: Spring Web,
The structure of this project follows the MavenModule structure (i.e. the same structure as generated from the initialzr tool).
For more information visit https://spring.io/quickstart
> ./mill test
...Test com.example.demo.DemoApplicationTests#contextLoads() finished...
> ./mill runBackground
> curl http://localhost:8096/hello
...Hello, World!...
> curl http://localhost:8096/hello?name=Mill
...Hello, Mill!...
> ./mill clean runBackground
> ./mill show assembly
.../out/assembly.dest/out.jar...
Spring Boot Hello World App
//| mill-jvm-version: 17
package build
import mill.*, javalib.*
object `package` extends JavaModule {
def mvnDeps = Seq(
mvn"org.springframework.boot:spring-boot-starter-web:2.5.6",
mvn"org.springframework.boot:spring-boot-starter-actuator:2.5.6"
)
object test extends JavaTests, TestModule.Junit5 {
def mvnDeps = super.mvnDeps() ++ Seq(
mvn"org.springframework.boot:spring-boot-starter-test:2.5.6"
)
}
}
This example demonstrates how to set up a simple Spring Boot webserver,
able to handle a single HTTP request at / and reply with a single response.
> ./mill test
...com.example.HelloSpringBootTest#shouldReturnDefaultMessage() finished...
> ./mill runBackground
> curl http://localhost:8086
...<h1>Hello, World!</h1>...
> ./mill clean runBackground
Spring Boot TodoMvc App
//| mill-jvm-version: 17
package build
import mill.*, javalib.*
object `package` extends JavaModule {
def mvnDeps = Seq(
mvn"org.springframework.boot:spring-boot-starter-data-jpa:2.5.4",
mvn"org.springframework.boot:spring-boot-starter-thymeleaf:2.5.4",
mvn"org.springframework.boot:spring-boot-starter-validation:2.5.4",
mvn"org.springframework.boot:spring-boot-starter-web:2.5.4",
mvn"javax.xml.bind:jaxb-api:2.3.1",
mvn"org.webjars:webjars-locator:0.41",
mvn"org.webjars.npm:todomvc-common:1.0.5",
mvn"org.webjars.npm:todomvc-app-css:2.4.1"
)
trait HelloTests extends JavaTests, TestModule.Junit5 {
def mainClass = Some("com.example.TodomvcApplication")
def mvnDeps = super.mvnDeps() ++ Seq(
mvn"org.springframework.boot:spring-boot-starter-test:2.5.6"
)
}
object test extends HelloTests {
def mvnDeps = super.mvnDeps() ++ Seq(
mvn"com.h2database:h2:2.3.230"
)
}
object integration extends HelloTests {
def mvnDeps = super.mvnDeps() ++ Seq(
mvn"org.testcontainers:testcontainers:1.18.0",
mvn"org.testcontainers:junit-jupiter:1.18.0",
mvn"org.testcontainers:postgresql:1.18.0",
mvn"org.postgresql:postgresql:42.6.0"
)
}
}
This is a larger example using Spring Boot, implementing the well known TodoMVC example app. Apart from running a webserver, this example also demonstrates:
-
Serving HTML templates using Thymeleaf
-
Serving static Javascript and CSS using Webjars
-
Querying a SQL database using JPA and H2
-
Unit testing using a H2 in-memory database
-
Integration testing using Testcontainers Postgres in Docker
> ./mill test
...com.example.TodomvcTests#homePageLoads() finished...
...com.example.TodomvcTests#addNewTodoItem() finished...
> ./mill integration
...com.example.TodomvcIntegrationTests#homePageLoads() finished...
...com.example.TodomvcIntegrationTests#addNewTodoItem() finished...
> ./mill test.runBackground
> curl http://localhost:8087
...<h1>todos</h1>...
> ./mill clean runBackground