Springboot
Spring Boot is a rapid development scaffold based on the Spring framework, simplifying the creation and deployment process of Spring applications. It provides features such as auto-configuration, embedded servers, and production-ready feature 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 later
- Installed Maven 3.6+ or Gradle
- Have a Tencent Cloud account with CloudBase service activated
- Have a basic understanding of Java and Spring Boot development
Step 1: Create a Spring Boot Application
💡 Tip: If you already have a Spring Boot application, you can skip this step.
Use Spring Initializr to create a project
- Visit start.spring.io
- Select the following configurations:
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)
- Click GENERATE to download the project zip file
- Extract to a local directory
Create Using Maven Commands (Optional)
mvn archetype:generate \
-DgroupId=com.tencent.cloudrun \
-DartifactId=cloudrun-springboot \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
cd cloudrun-springboot
Configure the pom.xml file
If you use Maven commands 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 Maven commands 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 the application:
cd cloudrun-springboot
mvn spring-boot:run
Open your browser and visit http://localhost:8080. You should see the default Spring Boot page.
Step 2: Add API Interface
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 succeeded", 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 the 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 not found");
}
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 the Health Check 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
# Logging Configuration
logging.level.com.tencent.cloudrun=INFO
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
Step 3: Local Testing
Start the Application
mvn spring-boot:run
Test the API Interface
# Testing Health Check
curl http://localhost:8080/health
# Home Page Testing
curl http://localhost:8080/
# Testing User List
curl http://localhost:8080/api/users
# Pagination Testing
curl "http://localhost:8080/api/users?page=1&limit=2"
# Testing Obtaining a Single User
curl http://localhost:8080/api/users/1
# Testing 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. Modify Application Configuration
Edit src/main/resources/application.properties to ensure the cloud function environment uses 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 Note: CloudBase HTTP cloud functions require the application to listen on port 9000, controlled via the environment variable
PORT=9000.
2. Create Startup Script
Create the scf_bootstrap file (without an extension):
#!/bin/bash
export PORT=9000
export JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC"
java $JAVA_OPTS -jar *.jar
💡 Note:
- Use the
*.jarwildcard to match JAR packages in the current directory- CloudBase cloud function will extract the uploaded files to the working directory, and JAR packages are directly located in the current directory.
Grant execute permission to the startup script:
chmod +x scf_bootstrap
3. Build JAR Package
mvn clean package -DskipTests
4. Project Structure
cloudrun-springboot/
├── src/
│ └── main/
│ ├── java/
│ └── resources/
├── target/
│ └── *.jar # Build artifact (such as: cloudrun-springboot-1.0-SNAPSHOT.jar)
├── pom.xml
├── scf_bootstrap # 🔑 Cloud function startup script
└── README.md
💡 Note:
scf_bootstrapis the startup script for CloudBase cloud functions- The cloud function will extract the uploaded files to the working directory, and JAR packages are directly located in the current directory.
- Set the
PORT=9000environment variable to ensure the application listens on the correct port- Configure JVM parameters to optimize memory usage
Step 5: Deploy Application
Deployment via the Console
⚠️ Note:
- java services start up slowly; it is recommended to adjust the function execution timeout to 30s
- Log in to the CloudBase Console
- Select your environment and go to the cloud function page
- Click "Create New Cloud Function"
- Select "HTTP Cloud Function"
- Fill in the function name (e.g.:
springboot-app) - Select runtime: Java 8 (or other supported versions)
- Select submission method: Local upload of code package
- Upload the built JAR package and the
scf_bootstrapfile - Automatic dependency installation: Disable (Not required for Java applications)
- Click the "Create" button and wait for deployment to complete
Deployment via CLI (Coming Soon)
Package and deploy
If manual packaging is required:
# Build 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 a custom domain for accessing 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 has the following advantages:
- Avoid path errors caused by changes in the project version number
- Simplify the deployment process without the need to modify the startup script each time
- Ensure that the built JAR package can be located regardless of its specific name
- The cloud function will extract the files to the current working directory; use relative paths.
Q: What if there are no JAR packages in the current directory?
A: Check the following points:
- Ensure to use the
zip -jparameter for packaging to avoid directory structure issues - Verify that the
mvn clean packagecommand executed successfully - Check whether the JAR package has been generated in the
targetdirectory - Ensure that the JAR package file is included during packaging
Q: Why use the zip -j parameter?
A: The -j parameter serves to "junk paths" (ignore directory structures):
- Using
zip -jignores the directory structure of files, saving only the files themselves - In this way,
target/cloudrun-springboot-1.0-SNAPSHOT.jarwill directly becomecloudrun-springboot-1.0-SNAPSHOT.jarafter extraction - Avoids the issue of multi-level directories like
/opt/target/in cloud functions - Simplifies the packaging process without the need to manually copy and delete 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
/optdirectory - JAR packages, configuration files, etc., will all be located under the
/optdirectory - This is the standard convention of the cloud function platform and does not require manual creation
- In the startup script, the absolute path
/opt/your-jar-file.jarmust be used to reference the JAR package
Q: Why must HTTP cloud functions 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 through the environment variable PORT=9000, while using port 8080 by default during local development.
Q: How to handle long cold startup times for Spring Boot applications?
A: You can optimize in the following ways:
- Enable
spring.main.lazy-initialization=true - Reduce auto-configured components
- Use GraalVM native images (experimental)
- Configure JVM parameters properly
Q: When running mvn spring-boot:run, it prompts "No plugin found for prefix 'spring-boot'", how to handle it?
A: This is because the project lacks Spring Boot Maven plugin configuration. Solution:
- Ensure
pom.xmlcontainsspring-boot-starter-parentas the parent project. - Add
spring-boot-maven-pluginin the<build><plugins>section - Refer to the complete
pom.xmlconfiguration example in the documentation
Q: How to handle the issue of excessively large JAR packages?
A:
- Use the
repackagegoal of thespring-boot-maven-plugin - Exclude unnecessary dependencies
- Use the
providedscope to exclude dependencies not required at runtime
Q: How to view Spring Boot logs in cloud functions?
A: On the CloudBase Console's cloud function page, click the function name to go to the details page and view the runtime logs.
Best Practices
1. Environment Variables 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 approaches, 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 Approaches:
# 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
- The
scf_bootstrapfile exists and has execute permission - Port configured to 9000
- JAR package built successfully and executable
- JVM parameters suitable for cloud function environments
- Enable lazy loading to optimize cold startup
- Test whether local startup functions properly
Next Steps
- Learn more about HTTP Cloud Function Configuration Options
- Learn how to connect to the CloudBase database