plugins { java // Apply the application plugin to add support for building a CLI application in Java. application id("com.gradleup.shadow") version "9.1.0" }
group = "com.taogen" version = "0.0.1-SNAPSHOT"
repositories { // Use Maven Central for resolving dependencies. mavenCentral() }
dependencies { // Use JUnit Jupiter for testing. testImplementation(libs.bundles.testing) testRuntimeOnly("org.junit.platform:junit-platform-launcher") // Logging implementation(libs.bundles.logging) // Lombok compileOnly(libs.lombok) annotationProcessor(libs.lombok) testCompileOnly(libs.lombok) testAnnotationProcessor(libs.lombok) // General utilities implementation(libs.bundles.generalUtilities) // JSON implementation(libs.bundles.json) }
// Apply a specific Java toolchain to ease working on different environments. java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
application { // Define the main class for the application. mainClass = "com.taogen.App" }
tasks.named<Test>("test") { // Use JUnit Platform for unit tests. useJUnitPlatform() }
tasks.jar { // Set a constant name for the JAR archiveFileName.set(project.name + ".jar") // Configure the JAR task to include the main class in the manifest. // Adds metadata to the JAR manifest manifest { attributes["Main-Class"] = "com.taogen.App"// Replace with your actual main class } }
<build> <!-- Set final jar name --> <finalName>${project.artifactId}</finalName> <plugins> <!-- Maven Shade Plugin: To package a fat JAR --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.6.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- Add manifest so you can run with java -jar --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.taogen.App</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
<dependencies> <!-- Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>${swagger.version}</version> </dependency> <!-- Developer Tools --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-docker-compose</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <!-- Using the provided scope ensures that the Lombok JAR is available for compilation but is not packaged into your final application artifact --> <scope>provided</scope> <version>${lombok.version}</version> </dependency> <!-- Testing --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- General utilities --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>${guava.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons-io.version}</version> </dependency> <!-- JSON --> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>${orgjson.version}</version> </dependency> <!-- Data Access --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>${mybatis-plus-boot.version}</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.mysql</groupId>--> <!-- <artifactId>mysql-connector-j</artifactId>--> <!-- <version>${mysql.version}</version>--> <!-- </dependency>--> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>${postgresql.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>
<build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <!-- With the goal added, you have to call only mvn package --> <!-- Otherwise you would need to call the plugin explicitly as mvn package spring-boot:repackage --> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <!-- To prevent lombok being packaged into jar --> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
Running with Maven
mvn spring-boot:run
Running with JAR
mvn package # or mvn package spring-boot:repackage # or skip tests mvn clean package -Dmaven.test.skip=true
# Enable Configuration Cache org.gradle.configuration-cache=true # Enable Build Cache (reuse build outputs between runs) org.gradle.caching=true # Parallel Execution (build independent modules at the same time) org.gradle.parallel=true # Configure Workers & Threads. Set based on your CPU cores (cores - 1 is often a good rule). org.gradle.workers.max=7 # Configure Incremental Compilation. Only recompile files that actually changed. kotlin.incremental=true java.incremental=true # Avoid Scanning for Updates When Not Needed. Only configures the modules you actually use in a build. org.gradle.configureondemand=true ######################################## # Optional tuning ######################################## # Setting JVM arguments for the Gradle daemon. Parallel & sensible JVM args org.gradle.jvmargs=-Xmx1g -XX:+UseParallelGC # Run Kotlin compiler in-process (faster for small/medium projects) kotlin.compiler.execution.strategy=in-process
services: postgres: image:'postgres:17-alpine' environment: -TZ=Asia/Shanghai # Note: Password can only be set on first startup. You can delete the volume to set a new password. -'POSTGRES_PASSWORD=${POSTGRES_PASSWORD}' volumes: -'postgres_data:/var/lib/postgresql/data' ports: -'${POSTGRES_PORT}:5432' redis: image:'redis:7-alpine' ports: -'${REDIS_PORT}:6379' command:'redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}' volumes: -'redis_data:/data'
compose-all.yml (Optional. Using spring-boot-docker-compose or this)
services: app: image:eclipse-temurin:21-alpine working_dir:/app command:./gradlewbootRun--no-daemon ports: -"8080:8080" env_file: -.env.docker volumes: # Mount project source code -.:/app # Mount Gradle cache from host -gradle-cache-1:/app/.gradle -gradle-cache-2:/root/.gradle postgres: image:'postgres:latest' environment: -TZ=Asia/Shanghai # Note: Password can only be set on first startup. You can delete the volume to set a new password. -'POSTGRES_PASSWORD=${POSTGRES_PASSWORD}' volumes: -'postgres_data:/var/lib/postgresql/data' ports: -'${POSTGRES_PORT}:5432' redis: image:'redis:7.2.4-alpine' ports: -'${REDIS_PORT}:6379' command:'redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}' volumes: -'redis_data:/data'
.env: This file stores environment variables specific to a particular deployment or development environment. It typically contains sensitive information such as API keys, database credentials, and other configuration settings that should not be committed to version control (e.g., Git). Applications read values from this file to configure their behavior at runtime. The .env file is usually excluded from version control using a .gitignore entry to prevent accidental exposure of sensitive data.
.env.example: A template or example of the .env file.
For example:
.env
# Postgres database information. The superuser username is postgres POSTGRES_HOST=localhost POSTGRES_PORT=5432 POSTGRES_USER=postgres POSTGRES_PASSWORD=YOUR_PASSWORD # Redis REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD=YOUR_PASSWORD
.env.docker
# Postgres database information. The superuser username is postgres POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_USER=postgres POSTGRES_PASSWORD=YOUR_PASSWORD # Redis REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD=YOUR_PASSWORD
# Get Java System Properties, VM Flags, VM Arguments, java_class_path jinfo <pid>
# Get VM Arguments jps -lvm | grep <pid>
VM Flags vs. VM Arguments
VM flags: specific options that configure the JVM’s operation
VM Arguments: includes all command-line arguments passed to the java command before the main class name. This includes: VM Flags, System Properties, Classpath Configuration.
VM Arguments = VM Flags + System Properties
Others
Specify SDK version
If you use SDKMAN to manage JDK versions, you can add the following configuration file to specify the SDK version of the project.
.sdkmanrc
# Enable auto-env through the sdkman_auto_env config # Add key=value pairs of SDKs to use below java=21.0.8-tem
.sdkmanrc for GraalVM native image
# Enable auto-env through the sdkman_auto_env config # Add key=value pairs of SDKs to use below java=21.0.8-graal