2025 终极 Bootique 教程:从入门到精通现代 Java 微服务开发
你还在为 Java 应用繁琐的配置和容器依赖而困扰吗?是否渴望一种能够快速构建独立运行、轻量级微服务的解决方案?Bootique——这个被称为"最小化意见"的 Java 开发平台,将彻底改变你的开发体验。本文将带你从零开始,掌握 Bootique 的核心概念、实战技巧与最佳实践,最终能够构建出高效、可维护的现代化 Java 应用。
读完本文,你将能够:
- 理解 Bootique 的核心架构与设计理念
- 快速搭建开发环境并创建第一个 Bootique 应用
- 掌握依赖注入、配置管理和命令行交互的关键技术
- 学会编写单元测试和集成测试,确保代码质量
- 构建和部署生产级别的 Bootique 微服务
- 解决实际开发中遇到的常见问题和性能瓶颈
Bootique 简介:重新定义 Java 开发体验
什么是 Bootique?
Bootique 是一个最小化意见(minimally opinionated)的现代可运行 Java 应用平台。它旨在帮助开发者构建容器无关的独立 Java 应用,无需传统的 JavaEE 容器。无论是 REST 服务、Web 应用、定时任务还是数据库迁移工具,Bootique 都能让你以命令行应用的简洁方式来开发和运行它们。
Bootique 的核心优势
| 特性 | Bootique | 传统 JavaEE | Spring Boot | |||||
|---|---|---|---|---|---|---|---|---|
| 容器依赖 | 无需容器,独立运行 | 需要应用服务器 | 嵌入式容器 | |||||
| 配置方式 | 灵活的 YAML/JSON 配置,支持环境变量覆盖 | XML 配置为主 | 注解+外部配置 | |||||
| 启动速度 | 极快(毫秒级) | 较慢(秒级) | 快(百毫秒级) | 内存占用 | 低 | 高 | 中 | |
| 学习曲线 | 平缓 | 陡峭 | 中等 | |||||
| 模块化 | 高度模块化,按需引入 | 模块耦合度高 | 自动配置,部分黑盒 |
架构概览
Bootique 的核心架构基于以下几个关键组件:
快速入门:你的第一个 Bootique 应用
开发环境准备
在开始之前,请确保你的开发环境满足以下要求:
- JDK 11 或更高版本
- Maven 3.6+ 或 Gradle 7.0+
- 任意 Java IDE(IntelliJ IDEA、Eclipse 等)
创建项目
首先,克隆 Bootique 仓库到本地:
git clone https://gitcode.com/gh_mirrors/bo/bootique.git
cd bootique
项目结构解析
Bootique 项目采用标准的 Maven/Gradle 项目结构,核心代码位于 src/main/java,测试代码位于 src/test/java。以下是一个典型的 Bootique 应用结构:
my-bootique-app/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── Application.java
│ │ │ ├── config/
│ │ │ ├── command/
│ │ │ └── module/
│ │ └── resources/
│ │ ├── config.yml
│ │ └── logback.xml
│ └── test/
│ └── java/
│ └── com/
│ └── example/
└── README.md
第一个应用:Hello World
让我们创建一个简单的 "Hello World" 应用,体验 Bootique 的简洁之处。
1. 添加依赖
在 pom.xml 中添加 Bootique 核心依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.bootique.bom</groupId>
<artifactId>bootique-bom</artifactId>
<version>3.0-RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.bootique.jersey</groupId>
<artifactId>bootique-jersey</artifactId>
</dependency>
<dependency>
<groupId>io.bootique.logback</groupId>
<artifactId>bootique-logback</artifactId>
</dependency>
</dependencies>
2. 创建主类
创建 src/main/java/com/example/Application.java:
package com.example;
import io.bootique.Bootique;
public class Application {
public static void main(String[] args) {
Bootique.app(args)
.autoLoadModules()
.exec()
.exit();
}
}
3. 添加 REST 资源
创建 src/main/java/com/example/HelloResource.java:
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class HelloResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello, Bootique!";
}
}
4. 创建模块
创建 src/main/java/com/example/HelloModule.java:
package com.example;
import com.google.inject.Binder;
import io.bootique.BQModule;
public class HelloModule implements BQModule {
@Override
public void configure(Binder binder) {
binder.bind(HelloResource.class);
}
}
5. 修改主类,注册模块
package com.example;
import io.bootique.Bootique;
public class Application {
public static void main(String[] args) {
Bootique.app(args)
.module(HelloModule.class)
.exec()
.exit();
}
}
6. 运行应用
mvn clean package
java -jar target/your-app-name.jar
现在,访问 http://localhost:8080/hello,你应该能看到 "Hello, Bootique!" 的响应。
核心概念:深入理解 Bootique
模块系统(Module System)
Bootique 的核心设计理念之一就是模块化。每个功能都被封装在独立的模块中,你可以根据需要选择引入。
模块类型
- 核心模块:由 Bootique 团队提供的基础功能模块
- 扩展模块:第三方开发的功能扩展模块
- 应用模块:你自己开发的业务逻辑模块
常用核心模块
| 模块名称 | 功能描述 |
|---|---|
| bootique-core | 核心功能,包括依赖注入、配置系统 |
| bootique-jersey | RESTful 服务支持(基于 Jersey) |
| bootique-logback | 日志系统(基于 Logback) |
| bootique-jetty | Web 服务器(基于 Jetty) |
| bootique-jdbc | 数据库访问 |
| bootique-mybatis | MyBatis ORM 集成 |
| bootique-cayenne | Cayenne ORM 集成 |
| bootique-jooq | jOOQ 集成 |
| bootique-cli | 命令行界面支持 |
模块注册方式
// 自动加载模块(推荐)
Bootique.app(args).autoLoadModules()
// 手动注册单个模块
Bootique.app(args).module(MyModule.class)
// 注册多个模块
Bootique.app(args)
.modules(MyModule1.class, MyModule2.class)
依赖注入(Dependency Injection)
Bootique 内置了一个轻量级的依赖注入(DI)容器,基于 JSR 330 标准。它负责管理对象的生命周期和依赖关系。
基本注入方式
import io.bootique.di.Inject;
public class MyService {
private final DependencyService dependency;
@Inject
public MyService(DependencyService dependency) {
this.dependency = dependency;
}
// ...
}
绑定配置
import com.google.inject.Binder;
import io.bootique.BQModule;
public class MyModule implements BQModule {
@Override
public void configure(Binder binder) {
binder.bind(MyService.class);
binder.bind(DependencyService.class).to(DefaultDependencyService.class);
}
}
提供者方法
import io.bootique.di.Provides;
import javax.inject.Singleton;
public class MyModule implements BQModule {
@Override
public void configure(Binder binder) {
// 模块配置
}
@Provides
@Singleton
public MyService provideMyService(DependencyService dependency) {
return new MyService(dependency);
}
}
配置系统(Configuration System)
Bootique 提供了灵活的配置系统,支持多种配置格式和加载方式。
配置文件格式
Bootique 支持 YAML、JSON 和 properties 格式的配置文件,其中 YAML 是推荐的格式:
# config.yml
server:
port: 8080
host: localhost
database:
url: jdbc:mysql://localhost:3306/mydb
user: ${DB_USER}
password: ${DB_PASSWORD}
logging:
level: INFO
配置加载顺序
Bootique 按照以下顺序加载配置,后面的配置会覆盖前面的:
- 默认配置(模块内置)
- 应用类路径下的
config.yml - 命令行指定的配置文件(
--config=myconfig.yml) - 环境变量
- 命令行参数
配置绑定
import io.bootique.annotation.BQConfig;
import io.bootique.annotation.BQConfigProperty;
@BQConfig
public class ServerConfig {
private int port;
private String host;
@BQConfigProperty("Server port")
public void setPort(int port) {
this.port = port;
}
@BQConfigProperty("Server host")
public void setHost(String host) {
this.host = host;
}
// getters...
}
在模块中绑定配置:
@Provides
@Singleton
public ServerConfig provideServerConfig(TypesFactory typesFactory, ConfigurationFactory configFactory) {
return configFactory.config(ServerConfig.class, typesFactory);
}
命令系统(Command System)
Bootique 应用本质上是命令行应用,每个功能都可以封装为一个命令。
创建自定义命令
import io.bootique.command.Command;
import io.bootique.command.CommandOutcome;
import io.bootique.cli.Cli;
public class GreetCommand implements Command {
@Override
public CommandOutcome run(Cli cli) {
String name = cli.optionString("name").orElse("Guest");
return CommandOutcome.succeeded("Hello, " + name + "!");
}
}
命令元数据
import io.bootique.meta.application.CommandMetadata;
public class GreetCommand implements Command {
@Override
public CommandMetadata getMetadata() {
return CommandMetadata.builder(GreetCommand.class)
.name("greet")
.description("Greets the user")
.addOption(OptionMetadata.builder("name")
.description("The name of the person to greet")
.build())
.build();
}
// run() method...
}
注册命令
public class GreetModule implements BQModule {
@Override
public void configure(Binder binder) {
Commands.contribute(binder)
.addCommand(GreetCommand.class);
}
}
运行命令
java -jar myapp.jar greet --name=John
高级特性与最佳实践
环境特定配置
在实际开发中,我们通常需要为不同环境(开发、测试、生产)使用不同的配置。Bootique 提供了多种方式来实现这一点。
使用配置文件后缀
config.yml # 基础配置
config-dev.yml # 开发环境配置
config-test.yml # 测试环境配置
config-prod.yml # 生产环境配置
启动时指定环境:
java -jar myapp.jar --config=config.yml --config=config-dev.yml
使用环境变量
database:
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:mydb}
user: ${DB_USER}
password: ${DB_PASSWORD}
使用配置 Profiles
profiles:
dev:
database:
url: jdbc:h2:mem:devdb
prod:
database:
url: jdbc:mysql://prod-db:3306/proddb
# 默认配置
database:
user: ${DB_USER}
password: ${DB_PASSWORD}
启动时激活 profile:
java -jar myapp.jar -Pprod
日志配置
Bootique 使用 Logback 作为默认日志框架,配置方式如下:
基本日志配置(logback.xml)
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.example" level="debug" />
</configuration>
通过 Bootique 配置文件配置日志
log:
level: INFO
appenders:
- type: console
pattern: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
- type: file
file: app.log
maxSize: 10MB
maxHistory: 10
测试策略
Bootique 提供了专门的测试模块 bootique-junit5,简化测试过程。
单元测试
import io.bootique.junit5.BQTest;
import io.bootique.junit5.BQTestFactory;
import io.bootique.junit5.BQApp;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
@BQTest
public class MyServiceTest {
@BQTestFactory
static BQTestFactory testFactory = new BQTestFactory();
@BQApp(modules = TestModule.class)
static BQRuntime app;
@Inject
MyService myService;
@Test
public void testService() {
assertEquals("test", myService.getValue());
}
}
集成测试
import io.bootique.junit5.BQTestTool;
import io.bootique.jetty.junit5.JettyTester;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HelloResourceTest {
@BQTestTool
static final JettyTester jetty = JettyTester.create();
@Test
public void testHello() {
jetty.target("/hello")
.request()
.get()
.then()
.statusCode(200)
.body("Hello, Bootique!");
}
}
应用监控与管理
Bootique 提供了多种监控和管理应用的方式。
健康检查
import io.bootique.metrics.health.HealthCheck;
import io.bootique.metrics.health.HealthCheckResult;
import io.bootique.metrics.health.HealthCheckStatus;
public class DatabaseHealthCheck implements HealthCheck {
private final DatabaseConnection connection;
public DatabaseHealthCheck(DatabaseConnection connection) {
this.connection = connection;
}
@Override
public HealthCheckResult check() {
try {
if (connection.isAlive()) {
return HealthCheckResult.builder()
.status(HealthCheckStatus.OK)
.message("Database connection is healthy")
.build();
} else {
return HealthCheckResult.builder()
.status(HealthCheckStatus.CRITICAL)
.message("Database connection is down")
.build();
}
} catch (Exception e) {
return HealthCheckResult.builder()
.status(HealthCheckStatus.CRITICAL)
.message("Health check failed: " + e.getMessage())
.build();
}
}
}
指标收集
import com.codahale.metrics.Counter;
import io.bootique.metrics.MetricsFactory;
public class MyService {
private final Counter requestCounter;
public MyService(MetricsFactory metricsFactory) {
this.requestCounter = metricsFactory.counter("requests");
}
public void processRequest() {
requestCounter.inc();
// ...
}
}
实战案例:构建 RESTful API 服务
让我们通过一个完整的案例来巩固所学知识,构建一个简单但功能完善的 RESTful API 服务。
项目结构
bootique-rest-api/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── Application.java
│ │ │ ├── config/
│ │ │ │ └── AppConfig.java
│ │ │ ├── model/
│ │ │ │ └── User.java
│ │ │ ├── repository/
│ │ │ │ ├── UserRepository.java
│ │ │ │ └── InMemoryUserRepository.java
│ │ │ ├── resource/
│ │ │ │ └── UserResource.java
│ │ │ └── module/
│ │ │ └── AppModule.java
│ │ └── resources/
│ │ ├── config.yml
│ │ └── logback.xml
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ ├── resource/
│ │ └── UserResourceTest.java
│ └── repository/
│ └── UserRepositoryTest.java
└── README.md
依赖配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.bootique.bom</groupId>
<artifactId>bootique-bom</artifactId>
<version>3.0-RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.bootique.jersey</groupId>
<artifactId>bootique-jersey</artifactId>
</dependency>
<dependency>
<groupId>io.bootique.logback</groupId>
<artifactId>bootique-logback</artifactId>
</dependency>
<dependency>
<groupId>io.bootique.jetty</groupId>
<artifactId>bootique-jetty</artifactId>
</dependency>
<dependency>
<groupId>io.bootique.junit5</groupId>
<artifactId>bootique-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
数据模型
package com.example.model;
public class User {
private String id;
private String name;
private String email;
// constructors, getters, setters
}
仓库接口与实现
package com.example.repository;
import com.example.model.User;
import java.util.List;
import java.util.Optional;
public interface UserRepository {
List<User> findAll();
Optional<User> findById(String id);
User create(User user);
User update(User user);
void delete(String id);
}
package com.example.repository;
import com.example.model.User;
import io.bootique.annotation.BQConfig;
import io.bootique.annotation.BQConfigProperty;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@BQConfig
public class InMemoryUserRepository implements UserRepository {
private final Map<String, User> users = new ConcurrentHashMap<>();
private final AtomicInteger idSequence = new AtomicInteger(1);
private int initialUsersCount = 0;
@BQConfigProperty("Number of initial test users to create")
public void setInitialUsersCount(int initialUsersCount) {
this.initialUsersCount = initialUsersCount;
}
@Override
public void init() {
// Create initial users if configured
for (int i = 0; i < initialUsersCount; i++) {
User user = new User();
user.setId(String.valueOf(idSequence.getAndIncrement()));
user.setName("User " + i);
user.setEmail("user" + i + "@example.com");
users.put(user.getId(), user);
}
}
// Other methods implementation...
}
REST 资源
package com.example.resource;
import com.example.model.User;
import com.example.repository.UserRepository;
import io.bootique.di.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
private final UserRepository userRepository;
@Inject
public UserResource(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GET
public List<User> getAllUsers() {
return userRepository.findAll();
}
@GET
@Path("/{id}")
public Response getUserById(@PathParam("id") String id) {
return userRepository.findById(id)
.map(Response::ok)
.orElse(Response.status(Response.Status.NOT_FOUND))
.build();
}
@POST
public Response createUser(User user) {
User created = userRepository.create(user);
return Response.status(Response.Status.CREATED)
.entity(created)
.build();
}
@PUT
@Path("/{id}")
public Response updateUser(@PathParam("id") String id, User user) {
user.setId(id);
return Response.ok(userRepository.update(user)).build();
}
@DELETE
@Path("/{id}")
public Response deleteUser(@PathParam("id") String id) {
userRepository.delete(id);
return Response.noContent().build();
}
}
应用模块
package com.example.module;
import com.example.repository.InMemoryUserRepository;
import com.example.repository.UserRepository;
import com.example.resource.UserResource;
import com.google.inject.Binder;
import io.bootique.BQModule;
import io.bootique.config.ConfigurationFactory;
import io.bootique.jersey.JerseyModule;
import io.bootique.jetty.JettyModule;
public class AppModule implements BQModule {
@Override
public void configure(Binder binder) {
// Configure Jersey resources
JerseyModule.extend(binder).addResource(UserResource.class);
// Configure Jetty
JettyModule.extend(binder);
// Bind repository
binder.bind(UserRepository.class).to(InMemoryUserRepository.class);
}
}
主类
package com.example;
import com.example.module.AppModule;
import io.bootique.Bootique;
public class Application {
public static void main(String[] args) {
Bootique.app(args)
.module(AppModule.class)
.exec()
.exit();
}
}
配置文件
jetty:
context: /api
port: 8080
repository:
initialUsersCount: 5
logging:
level: INFO
测试用例
package com.example.resource;
import com.example.module.AppModule;
import io.bootique.junit5.BQTest;
import io.bootique.junit5.BQTestFactory;
import io.bootique.junit5.BQApp;
import io.bootique.jetty.junit5.JettyTester;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
@BQTest
public class UserResourceTest {
@BQTestFactory
static BQTestFactory testFactory = new BQTestFactory();
@BQApp(modules = AppModule.class)
static BQRuntime app;
@Inject
JettyTester jetty;
@Test
public void testGetAllUsers() {
jetty.target("/users")
.request()
.get()
.then()
.statusCode(200)
.body("$.size()", org.hamcrest.Matchers.is(5));
}
@Test
public void testCreateUser() {
String userJson = "{\"name\":\"New User\",\"email\":\"new@example.com\"}";
jetty.target("/users")
.request()
.post(org.junit.jupiter.api.TestRequest.withBody(userJson))
.then()
.statusCode(201)
.body("name", org.hamcrest.Matchers.is("New User"));
}
}
部署与运维
构建可执行 JAR
使用 Maven 构建可执行 JAR:
mvn clean package
这将在 target 目录下生成一个可执行 JAR 文件。
运行应用
java -jar target/bootique-rest-api-1.0.jar
自定义 JVM 参数
java -Xmx512m -Dconfig=config-prod.yml -jar target/bootique-rest-api-1.0.jar
环境变量配置
export DB_HOST=prod-db.example.com
export DB_PORT=5432
export DB_USER=appuser
export DB_PASSWORD=secret
java -jar target/bootique-rest-api-1.0.jar
系统服务配置
Systemd 服务 (Linux)
创建 /etc/systemd/system/bootique-app.service:
[Unit]
Description=Bootique Application
After=network.target
[Service]
User=appuser
WorkingDirectory=/opt/bootique-app
ExecStart=/usr/bin/java -jar bootique-rest-api-1.0.jar
SuccessExitStatus=143
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
启用并启动服务:
sudo systemctl enable bootique-app
sudo systemctl start bootique-app
Windows 服务
使用 NSSM (Non-Sucking Service Manager) 将应用注册为 Windows 服务:
nssm install BootiqueApp "C:\Program Files\Java\jdk11\bin\java.exe" "-jar C:\apps\bootique-rest-api-1.0.jar"
常见问题与解决方案
问题:应用启动失败,提示端口已被占用
解决方案:
-
检查并关闭占用端口的进程:
# Linux/Mac lsof -i :8080 kill -9 <PID> # Windows netstat -ano | findstr :8080 taskkill /PID <PID> /F -
配置不同的端口:
java -jar myapp.jar --jetty.port=8081 -
在配置文件中设置:
jetty: port: 8081
问题:依赖注入失败,提示找不到实现类
解决方案:
-
确保接口和实现类都已正确注册:
binder.bind(MyInterface.class).to(MyImplementation.class); -
检查是否使用了正确的注解:
// 确保使用 @Inject 注解构造函数 @Inject public MyClass(MyDependency dependency) { // ... } -
检查模块是否已注册:
Bootique.app(args) .module(MyModule.class) // 确保模块已注册 .exec() .exit();
问题:配置文件未加载
解决方案:
-
检查配置文件位置是否正确(应放在 src/main/resources 目录下)
-
显式指定配置文件:
java -jar myapp.jar --config=path/to/config.yml -
检查配置文件格式是否正确(YAML/JSON 语法)
-
开启调试日志查看配置加载过程:
java -Dbootique.log.level=debug -jar myapp.jar
问题:应用启动缓慢
解决方案:
- 检查是否有不必要的模块被加载
- 优化依赖注入配置,避免循环依赖
- 检查数据库连接等外部资源是否可用
- 使用性能分析工具找出瓶颈:
java -jar myapp.jar --profile
总结与展望
Bootique 作为一个轻量级、模块化的 Java 开发平台,为构建现代化微服务提供了一种简洁高效的方式。它摒弃了传统 JavaEE 的复杂性,同时保持了足够的灵活性和扩展性,让开发者能够专注于业务逻辑而非框架配置。
通过本文的学习,你应该已经掌握了 Bootique 的核心概念和使用方法,包括模块系统、依赖注入、配置管理和命令系统等。我们还通过一个实战案例展示了如何构建一个完整的 RESTful API 服务,并探讨了部署和运维的最佳实践。
后续学习路径
-
深入学习特定模块:根据项目需求,深入学习 Bootique 的特定模块,如数据库访问、安全认证、缓存等。
-
探索高级特性:学习如何使用 Bootique 的高级特性,如 AOP、事件总线、异步处理等。
-
性能优化:研究 Bootique 应用的性能优化技巧,包括连接池配置、线程管理、缓存策略等。
-
生态系统:了解 Bootique 生态系统中的其他工具和库,如代码生成器、部署工具等。
Bootique 社区正在不断发展壮大,新的模块和功能不断涌现。保持关注官方文档和社区动态,将帮助你更好地利用这个强大的工具来构建出色的 Java 应用。
最后,鼓励你将 Bootique 应用到实际项目中,通过实践来深化理解。如有任何问题,欢迎参与社区讨论或查阅官方文档。
祝你的 Bootique 之旅愉快!
如果你觉得这篇文章对你有帮助,请点赞、收藏并关注作者,获取更多关于 Bootique 和 Java 开发的优质内容。下一篇我们将探讨 Bootique 与数据库的集成技巧,敬请期待!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



