Skip to main content

Springboot

Spring Boot is a rapid development scaffolding based on the Spring framework, simplifying the creation and deployment of Spring applications. It provides features such as auto-configuration, embedded servers, and production-ready monitoring, enabling developers to quickly build standalone, production-grade Spring applications.

This guide describes how to deploy Gin applications on CloudBase HTTP cloud functions.

For sample source code, see: cloudrun-springboot

Prerequisites

Before you begin, ensure that you have:

  • Installed JDK 8 or a later version
  • Installed Maven 3.6+ or Gradle
  • Have a Tencent Cloud account and have activated the CloudBase service
  • Have a basic knowledge of Java and Spring Boot development

Step 1: Create a Spring Boot Application

💡 Note: If you already have a Spring Boot application, you can skip this step.

Create a Project Using Spring Initializr

  1. Go to start.spring.io
  2. Select the following configuration:
Project: Maven
Language: Java
Spring Boot: 2.7.18 (or the latest stable version)
Project Metadata:
- Group: com.tencent
- Artifact: cloudrun-springboot
- Name: cloudrun-springboot
- Description: Demo project for Spring Boot
- Package name: com.tencent.cloudrun
- Packaging: Jar
- Java: 8
Dependencies:
- Spring Web
- Spring Boot Actuator (Health Check)
  1. Click GENERATE to download the project zip file
  2. Extract to a local directory

Create Using Maven Command (Optional)

mvn archetype:generate \
-DgroupId=com.tencent.cloudrun \
-DartifactId=cloudrun-springboot \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

cd cloudrun-springboot

Configuring the pom.xml File

If you use the Maven command to create the project, you need to manually configure the pom.xml file to support Spring Boot:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>

<groupId>com.tencent.cloudrun</groupId>
<artifactId>cloudrun-springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<name>cloudrun-springboot</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Create the main application class

If you use the Maven command to create the project, you also need to create the Spring Boot main application class.

Create CloudrunApplication.java in the src/main/java/com/tencent/cloudrun directory:

package com.tencent.cloudrun;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CloudrunApplication {

public static void main(String[] args) {
SpringApplication.run(CloudrunApplication.class, args);
}
}

Test the application locally

Go to the project directory and start up the application:

cd cloudrun-springboot
mvn spring-boot:run

Open the browser and go to http://localhost:8080. You should see the Spring Boot default page.

Step 2: Add API interfaces

Let's create some RESTful APIs to demonstrate the features of Spring Boot.

Create the User Entity Class

Create User.java in the src/main/java/com/tencent/cloudrun/entity directory:

package com.tencent.cloudrun.entity;

public class User {
private Long id;
private String name;
private String email;

// Constructor
public User() {}

public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}

// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }

public String getName() { return name; }
public void setName(String name) { this.name = name; }

public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}

Create the response wrapper class

Create ApiResponse.java in the src/main/java/com/tencent/cloudrun/dto directory:

package com.tencent.cloudrun.dto;

public class ApiResponse<T> {
private boolean success;
private String message;
private T data;

public ApiResponse(boolean success, String message, T data) {
this.success = success;
this.message = message;
this.data = data;
}

public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "Operation successful", data);
}

public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null);
}

// Getters and Setters
public boolean isSuccess() { return success; }
public void setSuccess(boolean success) { this.success = success; }

public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }

public T getData() { return data; }
public void setData(T data) { this.data = data; }
}

Create User Controller

Create UserController.java in the src/main/java/com/tencent/cloudrun/controller directory:

package com.tencent.cloudrun.controller;

import com.tencent.cloudrun.dto.ApiResponse;
import com.tencent.cloudrun.entity.User;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final List<User> users = new ArrayList<>();
private final AtomicLong counter = new AtomicLong();

public UserController() {
// Initialize test data
users.add(new User(counter.incrementAndGet(), "Zhang San", "zhangsan@example.com"));
users.add(new User(counter.incrementAndGet(), "Li Si", "lisi@example.com"));
users.add(new User(counter.incrementAndGet(), "Wang Wu", "wangwu@example.com"));
}

@GetMapping
public ApiResponse<List<User>> getAllUsers(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int limit) {

int startIndex = (page - 1) * limit;
int endIndex = Math.min(startIndex + limit, users.size());

if (startIndex >= users.size()) {
return ApiResponse.success(new ArrayList<>());
}

List<User> paginatedUsers = users.subList(startIndex, endIndex);
return ApiResponse.success(paginatedUsers);
}

@GetMapping("/{id}")
public ApiResponse<User> getUserById(@PathVariable Long id) {
User user = users.stream()
.filter(u -> u.getId().equals(id))
.findFirst()
.orElse(null);

if (user == null) {
return ApiResponse.error("User does not exist");
}

return ApiResponse.success(user);
}

@PostMapping
public ApiResponse<User> createUser(@RequestBody User user) {
if (user.getName() == null || user.getEmail() == null) {
return ApiResponse.error("Name and email cannot be empty");
}

user.setId(counter.incrementAndGet());
users.add(user);

return ApiResponse.success(user);
}
}

Create healthcheck controller

Create HealthController.java in the src/main/java/com/tencent/cloudrun/controller directory:

package com.tencent.cloudrun.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@RestController
public class HealthController {

@GetMapping("/health")
public Map<String, Object> health() {
Map<String, Object> health = new HashMap<>();
health.put("status", "healthy");
health.put("timestamp", LocalDateTime.now());
health.put("framework", "Spring Boot");
health.put("version", getClass().getPackage().getImplementationVersion());
health.put("java_version", System.getProperty("java.version"));

return health;
}

@GetMapping("/")
public Map<String, String> home() {
Map<String, String> response = new HashMap<>();
response.put("message", "Welcome to the Spring Boot CloudBase application!");
response.put("status", "running");

return response;
}
}

Configure application properties

Edit src/main/resources/application.properties:

# Server Configuration
server.port=${PORT:8080}
server.servlet.context-path=/

# Application Configuration
spring.application.name=cloudrun-springboot
management.endpoints.web.exposure.include=health,info

# Log Configuration
logging.level.com.tencent.cloudrun=INFO
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n

Step 3: Local Testing

Starting Up the Application

mvn spring-boot:run

Testing API Endpoints

# Test Health Check
curl http://localhost:8080/health

# Test Homepage
curl http://localhost:8080/

# Test User List
curl http://localhost:8080/api/users

# Test Pagination
curl "http://localhost:8080/api/users?page=1&limit=2"

# Test Obtaining a Single User
curl http://localhost:8080/api/users/1

# Test Creating a User
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"New User","email":"newuser@example.com"}'

Step 4: Prepare Deployment Files

HTTP cloud functions require the scf_bootstrap startup script and specific port configuration.

1. Update application configuration

Edit src/main/resources/application.properties to ensure cloud functions use port 9000:

# Cloud Function Port Configuration (default: 8080, cloud function environment uses 9000)
server.port=${PORT:8080}
server.servlet.context-path=/

# Application Configuration
spring.application.name=cloudrun-springboot
management.endpoints.web.exposure.include=health,info

⚠️ Important: CloudBase HTTP cloud functions require the application to listen on port 9000, controlled via the environment variable PORT=9000.

2. Create the Startup Script

💡 Note:

  • When creating the scf_bootstrap file on windows, it is recommended to use
  • When creating the scf_bootstrap file using vscode on windows, deploying to an HTTP cloud function may result in an error: scf_bootstrap file does not exist
  • This error occurs because the script file contains Windows-style carriage returns (^M), causing Linux to fail to recognize the interpreter path correctly. This is a common issue in WSL

Create the scf_bootstrap file (with no extension):

#!/bin/bash
export PORT=9000
export JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC"
java $JAVA_OPTS -jar *.jar

💡 Note:

  • Use the *.jar wildcard to match JAR packages in the current directory
  • CloudBase cloud function will extract the uploaded files to the working directory, with the JAR package located directly in the current directory

Grant execute permissions to the startup script:

chmod +x scf_bootstrap

3. Build the JAR Package

mvn clean package -DskipTests

4. Project Structure

cloudrun-springboot/
├── src/
│ └── main/
│ ├── java/
│ └── resources/
├── target/
│ └── *.jar # build artifact (for example: cloudrun-springboot-1.0-SNAPSHOT.jar)
├── pom.xml
├── scf_bootstrap # 🔑 Cloud function startup script
└── README.md

💡 Note:

  • scf_bootstrap is the startup script for CloudBase cloud functions
  • The cloud function will extract the uploaded files to the working directory, with the JAR package located directly in the current directory
  • Set the PORT=9000 environment variable to ensure the application listens on the correct port
  • Configure JVM parameters to optimize memory usage

Step 5: Deploy the Application

Deploy via the console

⚠️ Note:

  • java services start up slowly; it is recommended to adjust the function execution timeout to 30s
  1. Log in to the CloudBase console
  2. Select your environment and go to the cloud function page
  3. Click "New Cloud Function"
  4. Select "HTTP cloud function"
  5. Fill in the function name (such as: springboot-app)
  6. Select runtime: Java 8 (or other supported versions)
  7. Select submit method: Local code package upload
  8. Upload the built JAR package and the scf_bootstrap file
  9. Automatic dependency installation: Disable (Not required for Java applications)
  10. Click the "Create" button and wait for deployment to complete

Deploy via CLI

For details, see Deploy HTTP cloud function

Package and deploy

If you need to package manually:

# Build the application
mvn clean package -DskipTests

# Create deployment package (use the -j parameter to avoid directory structures)
zip -j springboot-app.zip target/*.jar scf_bootstrap

Step 6: Access Your Application

After successful deployment, you can refer to Accessing Cloud Functions via HTTP to set up custom domain access to HTTP cloud functions.

Example Request

# Health Check
curl https://your-app-url/health

# Obtain User List
curl https://your-app-url/api/users

# Pagination Query
curl "https://your-app-url/api/users?page=1&limit=2"

# Create New User
curl -X POST https://your-app-url/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com"}'

Frequently Asked Questions

Q: Why use *.jar instead of a specific JAR package name?

A: Using wildcards offers the following advantages:

  • Avoid path errors caused by project version number changes
  • Simplify the deployment process without the need to modify the startup script each time
  • Ensure the built JAR package can be located regardless of its specific name
  • The cloud function will extract files to the current working directory, and you can use relative paths

Q: What if there are no JAR packages in the current directory?

A: Check the following points:

  1. Ensure to use the zip -j parameter for packaging to avoid directory structure issues
  2. Verify that the mvn clean package command is executed successfully
  3. Check whether the JAR package has been generated in the target directory
  4. Ensure the package includes the JAR file

Q: Why use the zip -j parameter?

A: The -j parameter is used to "junk paths" (ignore paths):

  • Using zip -j ignores the directory structure and only saves the files themselves
  • This way, target/cloudrun-springboot-1.0-SNAPSHOT.jar will become cloudrun-springboot-1.0-SNAPSHOT.jar directly after extraction
  • Avoids multi-level directory issues such as /opt/target/ in cloud functions
  • Simplifies the packaging process without the need for manual copying and deleting of files

Q: What is the /opt directory in scf_bootstrap?

A: /opt is the standard working directory for the CloudBase cloud function runtime environment:

  • When you upload a code package to a cloud function, all files will be extracted to the /opt directory
  • JAR packages, configuration files, etc., will all be located in the /opt directory
  • This is the standard convention of the cloud function platform, requiring no manual creation
  • The startup script must use the absolute path /opt/your-jar-file.jar to reference the JAR package

Q: Why must the HTTP cloud function use port 9000?

A: CloudBase HTTP cloud functions require the application to listen on port 9000, which is the standard configuration of the platform. The application controls the port via the environment variable PORT=9000, and uses port 8080 by default during local development.

Q: How to handle the long cold startup time of Spring Boot applications?

A: It can be optimized in the following ways:

  • Enable spring.main.lazy-initialization=true
  • Reduce auto-configured components
  • Use GraalVM native images (experimental)
  • Appropriately configure JVM parameters

Q: What to do when running mvn spring-boot:run prompts "No plugin found for prefix 'spring-boot'"?

A: This is because the project lacks the Spring Boot Maven plugin configuration. Solution:

  1. Ensure the pom.xml includes spring-boot-starter-parent as the parent project
  2. Add the spring-boot-maven-plugin in the <build><plugins> section
  3. Refer to the complete pom.xml configuration example in the documentation

Q: How to handle the issue of excessively large JAR packages?

A:

  • Use the repackage goal of the spring-boot-maven-plugin
  • Exclude unnecessary dependencies
  • Use the provided scope to exclude dependencies not required at runtime

Q: How to view Spring Boot logs in cloud functions?

A: On the Cloud Functions page of the CloudBase console, click the function name to go to the details page and view the runtime logs.

Best Practices

1. Environment Variable Management

Use environment variables in application.properties:

# Database Configuration
spring.datasource.url=${DB_URL:jdbc:h2:mem:testdb}
spring.datasource.username=${DB_USERNAME:sa}
spring.datasource.password=${DB_PASSWORD:}

# Application Configuration
app.jwt.secret=${JWT_SECRET:mySecret}
app.upload.path=${UPLOAD_PATH:/tmp/uploads}

2. Port Configuration Policy

To support both deployment methods simultaneously, it is recommended to use dynamic port configuration:

# Support for multi-environment port configuration (default: 8080, cloud function environment controlled via PORT=9000)
server.port=${PORT:8080}

# Cloud Function Environment Detection
spring.profiles.active=${SPRING_PROFILES_ACTIVE:default}

3. Add Global Exception Handling

Create GlobalExceptionHandler.java:

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Exception.class)
public ApiResponse<String> handleException(Exception e) {
return ApiResponse.error("System error: " + e.getMessage());
}

@ExceptionHandler(IllegalArgumentException.class)
public ApiResponse<String> handleIllegalArgument(IllegalArgumentException e) {
return ApiResponse.error("Parameter error: " + e.getMessage());
}
}

4. Configure CORS support

Create WebConfig.java:

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}

5. JVM Parameter Optimization

JVM Optimization for Different Deployment Methods:

# HTTP Cloud Function (Memory-Constrained)
JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

# Cloud Hosting (More Resources)
JAVA_OPTS="-Xmx1g -Xms512m -XX:+UseG1GC"

6. Health Check Enhancement

Custom health check indicator:

@Component
public class CustomHealthIndicator implements HealthIndicator {

@Override
public Health health() {
// Check application status
boolean isHealthy = checkApplicationHealth();

if (isHealthy) {
return Health.up()
.withDetail("status", "Application running normally")
.withDetail("timestamp", LocalDateTime.now())
.build();
} else {
return Health.down()
.withDetail("status", "Application abnormal")
.build();
}
}

private boolean checkApplicationHealth() {
// Implement specific health check logic
return true;
}
}

7. Pre-deployment Checklist

  • scf_bootstrap file exists and has execute permission
  • Port is configured to 9000
  • JAR package is built successfully and executable
  • JVM parameters are suitable for the cloud function environment
  • Enable lazy loading to optimize cold startup
  • Local startup is tested and functioning normally

Next steps