Spring Boot 4.0 整合 MyBatis-Plus 完整教程
注:Spring Boot 4.0 ,本教程基于 Spring Boot 4.0 的预览版和新特性预期进行构建。实际发布时可能会有调整。
一、Spring Boot 4.0 新特性概述
1.1 主要新特性
- Java 21+ 支持:基于虚拟线程的响应式编程增强
- GraalVM 原生镜像优化:更完善的 AOT 编译支持
- 响应式编程增强:更好的响应式 MyBatis 支持
- 模块化改进:更好的 Java Module 支持
- AI/机器学习集成:内置 AI 功能支持
1.2 构建工具要求
- JDK 21+
- Maven 3.9+ 或 Gradle 8.5+
- GraalVM 23.0+(可选,用于原生编译)
二、项目初始化
2.1 使用 Spring Initializr
# 使用官方 Initializrcurlhttps://start.spring.io/starter.zip\-dtype=maven-project\-dlanguage=java\-dbootVersion=4.0.0-M1\-dbaseDir=spring-boot4-mybatisplus\-dgroupId=com.example\-dartifactId=demo\-dname=demo\-ddescription=Demo+project+for+Spring+Boot+4.0+with+MyBatis-Plus\-dpackageName=com.example.demo\-dpackaging=jar\-djavaVersion=21\-ddependencies=web,data-jpa\-o demo.zip2.2 手动创建 pom.xml
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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>4.0.0-M1</version><relativePath/></parent><groupId>com.example</groupId><artifactId>springboot4-mybatisplus</artifactId><version>1.0.0</version><name>springboot4-mybatisplus</name><description>Spring Boot 4.0 with MyBatis-Plus</description><properties><java.version>21</java.version><mybatis-plus.version>3.5.5</mybatis-plus.version><graalvm.version>23.0.0</graalvm.version></properties><dependencies><!-- Spring Boot 4.0 核心依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 响应式 Web 支持(新特性) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- MyBatis-Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!-- 数据库驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- 响应式 MySQL 驱动(新特性) --><dependency><groupId>io.asyncer</groupId><artifactId>r2dbc-mysql</artifactId><scope>runtime</scope></dependency><!-- 响应式 R2DBC --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- GraalVM 原生镜像支持(新特性) --><dependency><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 响应式测试支持 --><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><!-- Spring Boot Maven 插件,支持 AOT --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder-jammy-tiny:latest</builder><env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env></image></configuration></plugin><!-- GraalVM Native Image 插件 --><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>${graalvm.version}</version><extensions>true</extensions><executions><execution><id>build-native</id><goals><goal>compile-no-fork</goal></goals><phase>package</phase></execution></executions></plugin></plugins></build><!-- Spring Milestone 仓库 --><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories></project>三、配置 MyBatis-Plus
3.1 应用配置(application.yml)
# Spring Boot 4.0 新配置格式spring:application:name:springboot4-mybatisplus# 数据源配置(虚拟线程优化)datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername:rootpassword:123456hikari:# 虚拟线程池配置(Spring Boot 4.0 新特性)thread-factory:org.springframework.boot.jdbc.VirtualThreadExecutor# 响应式数据源(新特性)r2dbc:url:r2dbc:mysql://localhost:3306/mybatis_plus_demousername:rootpassword:123456# AOT 编译配置aot:enabled:truegenerate-code:true# GraalVM 原生镜像配置native:mode:nativedebug:true# MyBatis-Plus 配置mybatis-plus:configuration:# 自动映射行为auto-mapping-behavior:full# 驼峰命名转换map-underscore-to-camel-case:true# 日志实现log-impl:org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:# 逻辑删除字段名logic-delete-field:deleted# 逻辑删除值logic-delete-value:1# 逻辑未删除值logic-not-delete-value:0# 主键类型id-type:auto# 分页插件配置pagehelper:helper-dialect:mysqlreasonable:truesupport-methods-arguments:true# 日志配置logging:level:com.example.demo.mapper:debugorg.springframework.r2dbc:debugpattern:console:"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"# 虚拟线程配置(Spring Boot 4.0 新特性)server:tomcat:threads:# 使用虚拟线程use-virtual-threads:true# 响应式服务器配置netty:connection-timeout:2m3.2 MyBatis-Plus 配置类
packagecom.example.demo.config;importcom.baomidou.mybatisplus.annotation.DbType;importcom.baomidou.mybatisplus.core.handlers.MetaObjectHandler;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;importorg.apache.ibatis.reflection.MetaObject;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.transaction.annotation.EnableTransactionManagement;importjava.time.LocalDateTime;/** * MyBatis-Plus 配置类 * 使用 Spring Boot 4.0 新特性:虚拟线程兼容性配置 */@Configuration@EnableTransactionManagement@MapperScan("com.example.demo.mapper")publicclassMyBatisPlusConfig{/** * MyBatis-Plus 拦截器配置 * 支持分页、乐观锁、防全表更新与删除 */@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();// 分页插件interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));// 乐观锁插件interceptor.addInnerInterceptor(newOptimisticLockerInnerInterceptor());// 防止全表更新与删除interceptor.addInnerInterceptor(newBlockAttackInnerInterceptor());returninterceptor;}/** * 元数据处理器 - 自动填充字段 */@BeanpublicMetaObjectHandlermetaObjectHandler(){returnnewMetaObjectHandler(){@OverridepublicvoidinsertFill(MetaObjectmetaObject){// 使用虚拟线程安全的日期时间this.strictInsertFill(metaObject,"createTime",LocalDateTime.class,LocalDateTime.now());this.strictInsertFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());this.strictInsertFill(metaObject,"version",Integer.class,1);}@OverridepublicvoidupdateFill(MetaObjectmetaObject){this.strictUpdateFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());}};}}四、实体类与 Mapper
4.1 基础实体类
packagecom.example.demo.entity;importcom.baomidou.mybatisplus.annotation.*;importlombok.Data;importlombok.experimental.Accessors;importjava.io.Serializable;importjava.time.LocalDateTime;/** * 基础实体类 * 使用 Java 21 Record 模式(预览特性) */@Data@Accessors(chain=true)publicclassBaseEntityimplementsSerializable{/** * 主键ID - 使用虚拟线程安全的ID生成策略 */@TableId(type=IdType.ASSIGN_ID)privateLongid;/** * 创建时间 */@TableField(fill=FieldFill.INSERT)privateLocalDateTimecreateTime;/** * 更新时间 */@TableField(fill=FieldFill.INSERT_UPDATE)privateLocalDateTimeupdateTime;/** * 创建人 */@TableField(fill=FieldFill.INSERT)privateStringcreateBy;/** * 更新人 */@TableField(fill=FieldFill.INSERT_UPDATE)privateStringupdateBy;/** * 乐观锁版本号 */@Version@TableField(fill=FieldFill.INSERT)privateIntegerversion;/** * 逻辑删除标志 */@TableLogic@TableField(fill=FieldFill.INSERT)privateIntegerdeleted;}4.2 用户实体类
packagecom.example.demo.entity;importcom.baomidou.mybatisplus.annotation.TableField;importcom.baomidou.mybatisplus.annotation.TableName;importlombok.Data;importlombok.EqualsAndHashCode;importlombok.experimental.Accessors;/** * 用户实体类 * 使用 Spring Boot 4.0 新特性:虚拟线程安全的序列化 */@Data@EqualsAndHashCode(callSuper=true)@Accessors(chain=true)@TableName("sys_user")publicclassUserextendsBaseEntity{/** * 用户名 */privateStringusername;/** * 密码 */privateStringpassword;/** * 邮箱 */privateStringemail;/** * 手机号 */privateStringphone;/** * 状态:0-禁用,1-启用 */privateIntegerstatus;/** * 虚拟线程安全的额外字段 * 使用 transient 避免序列化问题 */@TableField(exist=false)privatetransientStringvirtualThreadInfo;}4.3 Mapper 接口
packagecom.example.demo.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.example.demo.entity.User;importorg.apache.ibatis.annotations.Mapper;importorg.apache.ibatis.annotations.Select;importorg.springframework.data.repository.query.Param;importorg.springframework.r2dbc.core.DatabaseClient;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;/** * 用户 Mapper * 支持响应式查询(Spring Boot 4.0 新特性) */@MapperpublicinterfaceUserMapperextendsBaseMapper<User>{/** * 传统阻塞式查询 */@Select("SELECT * FROM sys_user WHERE username = #{username}")UserselectByUsername(@Param("username")Stringusername);/** * 响应式查询 - 返回单个结果 * 使用虚拟线程安全的方式 */@Select("SELECT * FROM sys_user WHERE id = #{id}")defaultMono<User>selectReactiveById(Longid,DatabaseClientdatabaseClient){returndatabaseClient.sql("SELECT * FROM sys_user WHERE id = :id").bind("id",id).map((row,metadata)->{Useruser=newUser();user.setId(row.get("id",Long.class));user.setUsername(row.get("username",String.class));user.setEmail(row.get("email",String.class));user.setStatus(row.get("status",Integer.class));returnuser;}).one();}/** * 响应式查询 - 返回多个结果 */@Select("SELECT * FROM sys_user WHERE status = #{status}")defaultFlux<User>selectReactiveByStatus(Integerstatus,DatabaseClientdatabaseClient){returndatabaseClient.sql("SELECT * FROM sys_user WHERE status = :status").bind("status",status).map((row,metadata)->{Useruser=newUser();user.setId(row.get("id",Long.class));user.setUsername(row.get("username",String.class));user.setEmail(row.get("email",String.class));user.setStatus(row.get("status",Integer.class));returnuser;}).all();}}五、Service 层实现
5.1 接口定义
packagecom.example.demo.service;importcom.baomidou.mybatisplus.extension.service.IService;importcom.example.demo.entity.User;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.util.concurrent.CompletableFuture;/** * 用户服务接口 * 支持响应式和虚拟线程 */publicinterfaceUserServiceextendsIService<User>{/** * 虚拟线程方式查询用户 * Spring Boot 4.0 新特性 */CompletableFuture<User>findUserByUsernameVirtualThread(Stringusername);/** * 响应式查询用户 */Mono<User>findUserByIdReactive(Longid);/** * 响应式查询用户列表 */Flux<User>findUsersByStatusReactive(Integerstatus);/** * 使用结构化并发(Java 21 新特性) */UserfindUserWithStructuredConcurrency(Longid);}5.2 服务实现
packagecom.example.demo.service.impl;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importcom.example.demo.entity.User;importcom.example.demo.mapper.UserMapper;importcom.example.demo.service.UserService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.r2dbc.core.DatabaseClient;importorg.springframework.stereotype.Service;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.StructuredTaskScope;importjava.util.concurrent.TimeUnit;/** * 用户服务实现 * 使用 Spring Boot 4.0 新特性:虚拟线程和响应式编程 */@Slf4j@Service@RequiredArgsConstructorpublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService{privatefinalUserMapperuserMapper;privatefinalDatabaseClientdatabaseClient;@OverridepublicCompletableFuture<User>findUserByUsernameVirtualThread(Stringusername){returnCompletableFuture.supplyAsync(()->{// 在虚拟线程中执行try{// 模拟耗时操作Thread.sleep(100);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}returnuserMapper.selectOne(newLambdaQueryWrapper<User>().eq(User::getUsername,username));},Thread.ofVirtual().factory());}@OverridepublicMono<User>findUserByIdReactive(Longid){returnuserMapper.selectReactiveById(id,databaseClient).doOnNext(user->log.info("Found user reactively: {}",user.getUsername()));}@OverridepublicFlux<User>findUsersByStatusReactive(Integerstatus){returnuserMapper.selectReactiveByStatus(status,databaseClient).doOnNext(user->log.info("Streaming user: {}",user.getUsername()));}@OverridepublicUserfindUserWithStructuredConcurrency(Longid){// Java 21 结构化并发try(varscope=newStructuredTaskScope.ShutdownOnFailure()){varuserFuture=scope.fork(()->userMapper.selectById(id));varuserDetailsFuture=scope.fork(()->// 模拟获取用户详情"User Details for ID: "+id);scope.join();scope.throwIfFailed();Useruser=userFuture.get();if(user!=null){user.setVirtualThreadInfo(userDetailsFuture.get());}returnuser;}catch(InterruptedExceptione){Thread.currentThread().interrupt();thrownewRuntimeException("Task interrupted",e);}catch(Exceptione){thrownewRuntimeException("Failed to fetch user",e);}}/** * 批量保存用户 - 使用虚拟线程优化 */publicvoidsaveUsersWithVirtualThreads(List<User>users){try(varscope=newStructuredTaskScope.ShutdownOnFailure()){List<StructuredTaskScope.Subtask<User>>tasks=users.stream().map(user->scope.fork(()->{// 每个用户保存操作在独立的虚拟线程中执行save(user);returnuser;})).toList();scope.join();scope.throwIfFailed();// 处理结果tasks.forEach(task->log.info("Saved user: {}",task.get().getUsername()));}catch(InterruptedExceptione){Thread.currentThread().interrupt();thrownewRuntimeException("Save interrupted",e);}catch(Exceptione){thrownewRuntimeException("Failed to save users",e);}}}六、Controller 层
6.1 传统 REST Controller
packagecom.example.demo.controller;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.baomidou.mybatisplus.core.metadata.IPage;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importjava.util.List;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;/** * 用户控制器 * 支持虚拟线程和传统阻塞模式 */@Slf4j@RestController@RequestMapping("/api/v1/users")@RequiredArgsConstructorpublicclassUserController{privatefinalUserServiceuserService;/** * 创建用户 */@PostMappingpublicResponseEntity<User>create(@RequestBodyUseruser){booleansaved=userService.save(user);returnsaved?ResponseEntity.ok(user):ResponseEntity.badRequest().build();}/** * 分页查询用户 * 使用虚拟线程优化 */@GetMapping("/page")publicResponseEntity<IPage<User>>page(@RequestParam(defaultValue="1")Integercurrent,@RequestParam(defaultValue="10")Integersize){Page<User>page=newPage<>(current,size);IPage<User>result=userService.page(page);returnResponseEntity.ok(result);}/** * 使用虚拟线程查询用户 * Spring Boot 4.0 新特性 */@GetMapping("/virtual/{username}")publicResponseEntity<User>findByUsernameVirtual(@PathVariableStringusername)throwsExecutionException,InterruptedException{CompletableFuture<User>future=userService.findUserByUsernameVirtualThread(username);returnResponseEntity.ok(future.get());}/** * 使用结构化并发查询用户 * Java 21 新特性 */@GetMapping("/structured/{id}")publicResponseEntity<User>findWithStructuredConcurrency(@PathVariableLongid){Useruser=userService.findUserWithStructuredConcurrency(id);returnResponseEntity.ok(user);}/** * 批量创建用户 - 使用虚拟线程 */@PostMapping("/batch/virtual")publicResponseEntity<Void>createBatchVirtual(@RequestBodyList<User>users){// 在新线程中执行批量操作Thread.ofVirtual().start(()->{userService.saveUsersWithVirtualThreads(users);});returnResponseEntity.accepted().build();}}6.2 响应式 Controller
packagecom.example.demo.controller;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.time.Duration;/** * 响应式用户控制器 * Spring Boot 4.0 响应式增强 */@Slf4j@RestController@RequestMapping("/api/v2/users")@RequiredArgsConstructorpublicclassUserReactiveController{privatefinalUserServiceuserService;/** * 响应式查询单个用户 */@GetMapping("/reactive/{id}")publicMono<ResponseEntity<User>>findByIdReactive(@PathVariableLongid){returnuserService.findUserByIdReactive(id).map(ResponseEntity::ok).defaultIfEmpty(ResponseEntity.notFound().build());}/** * 响应式查询用户列表 */@GetMapping(value="/reactive/stream",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<User>streamByStatus(@RequestParamIntegerstatus){returnuserService.findUsersByStatusReactive(status).delayElements(Duration.ofMillis(100))// 模拟流式处理.doOnNext(user->log.info("Streaming user: {}",user.getUsername()));}/** * SSE 流式传输 */@GetMapping(value="/sse",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>userEvents(){returnFlux.interval(Duration.ofSeconds(1)).map(sequence->String.format("User Event %d at %s",sequence,java.time.LocalTime.now()));}}七、响应式 Repository
packagecom.example.demo.repository;importcom.example.demo.entity.User;importorg.springframework.data.r2dbc.repository.R2dbcRepository;importorg.springframework.data.r2dbc.repository.Query;importorg.springframework.stereotype.Repository;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;/** * 响应式用户仓库 * Spring Boot 4.0 响应式数据访问 */@RepositorypublicinterfaceUserReactiveRepositoryextendsR2dbcRepository<User,Long>{/** * 根据用户名查询 */@Query("SELECT * FROM sys_user WHERE username = :username")Mono<User>findByUsername(Stringusername);/** * 根据状态查询 */@Query("SELECT * FROM sys_user WHERE status = :status")Flux<User>findByStatus(Integerstatus);/** * 分页查询 */@Query("SELECT * FROM sys_user ORDER BY create_time DESC LIMIT :limit OFFSET :offset")Flux<User>findAllWithPagination(intlimit,intoffset);}八、全局异常处理
packagecom.example.demo.handler;importcom.baomidou.mybatisplus.core.exceptions.MybatisPlusException;importlombok.extern.slf4j.Slf4j;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.RestControllerAdvice;importorg.springframework.web.bind.support.WebExchangeBindException;importreactor.core.publisher.Mono;importjava.util.HashMap;importjava.util.Map;/** * 全局异常处理器 * 支持响应式异常处理 */@Slf4j@RestControllerAdvicepublicclassGlobalExceptionHandler{/** * 处理 MyBatis-Plus 异常 */@ExceptionHandler(MybatisPlusException.class)publicResponseEntity<Map<String,Object>>handleMybatisPlusException(MybatisPlusExceptione){log.error("MyBatis-Plus Exception: {}",e.getMessage(),e);Map<String,Object>response=newHashMap<>();response.put("code",HttpStatus.INTERNAL_SERVER_ERROR.value());response.put("message","数据库操作失败");response.put("detail",e.getMessage());response.put("timestamp",System.currentTimeMillis());returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);}/** * 处理虚拟线程中断异常 */@ExceptionHandler(InterruptedException.class)publicResponseEntity<Map<String,Object>>handleInterruptedException(InterruptedExceptione){log.warn("Virtual thread interrupted: {}",e.getMessage());Map<String,Object>response=newHashMap<>();response.put("code",HttpStatus.SERVICE_UNAVAILABLE.value());response.put("message","请求被中断");response.put("timestamp",System.currentTimeMillis());Thread.currentThread().interrupt();// 恢复中断状态returnResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response);}/** * 响应式异常处理 */@ExceptionHandler(WebExchangeBindException.class)publicMono<ResponseEntity<Map<String,Object>>>handleBindException(WebExchangeBindExceptione){returnMono.fromCallable(()->{Map<String,Object>response=newHashMap<>();response.put("code",HttpStatus.BAD_REQUEST.value());response.put("message","参数验证失败");Map<String,String>errors=newHashMap<>();e.getFieldErrors().forEach(error->errors.put(error.getField(),error.getDefaultMessage()));response.put("errors",errors);response.put("timestamp",System.currentTimeMillis());returnResponseEntity.badRequest().body(response);});}}九、虚拟线程配置
packagecom.example.demo.config;importorg.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;importorg.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.task.AsyncTaskExecutor;importorg.springframework.core.task.support.TaskExecutorAdapter;importorg.springframework.scheduling.annotation.EnableAsync;importjava.util.concurrent.Executors;/** * 虚拟线程配置 * Spring Boot 4.0 核心新特性 */@Configuration@EnableAsyncpublicclassVirtualThreadConfig{/** * 配置 Tomcat 使用虚拟线程 */@BeanpublicTomcatProtocolHandlerCustomizer<?>protocolHandlerVirtualThreadExecutorCustomizer(){returnprotocolHandler->protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());}/** * 配置 Spring 异步任务执行器使用虚拟线程 */@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)publicAsyncTaskExecutorasyncTaskExecutor(){returnnewTaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());}/** * 配置虚拟线程池用于数据库操作 */@Beanpublicjava.util.concurrent.ExecutorServicedatabaseExecutor(){returnExecutors.newThreadPerTaskExecutor(Thread.ofVirtual().name("db-virtual-thread-",0).factory());}}十、AOT 和原生镜像支持
10.1 创建 AOT 处理类
packagecom.example.demo.aot;importorg.springframework.aot.hint.RuntimeHints;importorg.springframework.aot.hint.RuntimeHintsRegistrar;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.ImportRuntimeHints;/** * AOT 运行时提示注册 * Spring Boot 4.0 原生镜像支持 */@Configuration@ImportRuntimeHints(AotRuntimeHints.MybatisPlusRuntimeHints.class)publicclassAotRuntimeHints{staticclassMybatisPlusRuntimeHintsimplementsRuntimeHintsRegistrar{@OverridepublicvoidregisterHints(RuntimeHintshints,ClassLoaderclassLoader){// 注册反射hints.reflection().registerType(com.baomidou.mybatisplus.core.mapper.BaseMapper.class,hint->hint.withMembers(org.springframework.aot.hint.MemberCategory.INVOKE_PUBLIC_METHODS));// 注册资源hints.resources().registerPattern("mapper/*.xml");hints.resources().registerPattern("mybatis-config.xml");// 注册序列化hints.serialization().registerType(com.example.demo.entity.User.class);// 注册代理hints.proxies().registerJdkProxy(org.apache.ibatis.binding.MapperProxy.class);}}}10.2 native-image.properties
Args = --enable-url-protocols=http,https \ -H:+ReportExceptionStackTraces \ -H:+ReportUnsupportedElementsAtRuntime \ --initialize-at-build-time=com.mysql.cj \ --initialize-at-run-time=io.netty.handler.codec.http.HttpObjectEncoder \ -H:IncludeResourceBundles=com.mysql.cj.LocalizedErrorMessages十一、测试类
packagecom.example.demo;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importlombok.extern.slf4j.Slf4j;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importreactor.core.publisher.Mono;importreactor.test.StepVerifier;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;importstaticorg.assertj.core.api.Assertions.assertThat;/** * 集成测试 * 测试虚拟线程和响应式功能 */@Slf4j@SpringBootTestclassSpringBoot4MybatisPlusApplicationTests{@AutowiredprivateUserServiceuserService;/** * 测试虚拟线程查询 */@TestvoidtestVirtualThreadQuery()throwsExecutionException,InterruptedException,TimeoutException{// 准备测试数据Useruser=newUser().setUsername("test_virtual").setEmail("test@example.com").setStatus(1);userService.save(user);// 使用虚拟线程查询CompletableFuture<User>future=userService.findUserByUsernameVirtualThread("test_virtual");Userresult=future.get(5,TimeUnit.SECONDS);assertThat(result).isNotNull();assertThat(result.getUsername()).isEqualTo("test_virtual");log.info("Virtual thread test passed, user ID: {}",result.getId());}/** * 测试响应式查询 */@TestvoidtestReactiveQuery(){// 准备测试数据Useruser=newUser().setUsername("test_reactive").setEmail("reactive@example.com").setStatus(1);userService.save(user);// 使用响应式查询Mono<User>userMono=userService.findUserByIdReactive(user.getId());StepVerifier.create(userMono).assertNext(foundUser->{assertThat(foundUser).isNotNull();assertThat(foundUser.getUsername()).isEqualTo("test_reactive");}).verifyComplete();log.info("Reactive query test passed");}/** * 测试结构化并发 */@TestvoidtestStructuredConcurrency(){// 准备测试数据Useruser=newUser().setUsername("test_structured").setEmail("structured@example.com").setStatus(1);userService.save(user);// 使用结构化并发查询Userresult=userService.findUserWithStructuredConcurrency(user.getId());assertThat(result).isNotNull();assertThat(result.getUsername()).isEqualTo("test_structured");assertThat(result.getVirtualThreadInfo()).contains("User Details");log.info("Structured concurrency test passed");}/** * 测试批量虚拟线程操作 */@TestvoidtestBatchVirtualThreads(){// 准备测试数据List<User>users=newArrayList<>();for(inti=0;i<10;i++){users.add(newUser().setUsername("batch_user_"+i).setEmail("batch"+i+"@example.com").setStatus(1));}// 使用虚拟线程批量保存userService.saveUsersWithVirtualThreads(users);// 验证保存结果List<User>savedUsers=userService.list(newLambdaQueryWrapper<User>().likeRight(User::getUsername,"batch_user_"));assertThat(savedUsers).hasSize(10);log.info("Batch virtual threads test passed, saved {} users",savedUsers.size());}}十二、性能监控
packagecom.example.demo.monitor;importio.micrometer.core.instrument.MeterRegistry;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;importorg.springframework.util.StopWatch;importjava.util.concurrent.atomic.AtomicInteger;/** * 虚拟线程性能监控 * Spring Boot 4.0 监控增强 */@Slf4j@Aspect@Component@RequiredArgsConstructorpublicclassVirtualThreadMonitor{privatefinalMeterRegistrymeterRegistry;privatefinalAtomicIntegeractiveVirtualThreads=newAtomicInteger(0);/** * 监控虚拟线程使用 */@Around("@annotation(com.example.demo.annotation.VirtualThreadMonitor)")publicObjectmonitorVirtualThread(ProceedingJoinPointjoinPoint)throwsThrowable{StopWatchstopWatch=newStopWatch();intcurrentThreads=activeVirtualThreads.incrementAndGet();try{stopWatch.start();Objectresult=joinPoint.proceed();stopWatch.stop();// 记录指标meterRegistry.timer("virtual.thread.execution.time").record(stopWatch.getTotalTimeNanos(),java.util.concurrent.TimeUnit.NANOSECONDS);meterRegistry.gauge("virtual.thread.active.count",activeVirtualThreads);log.info("Virtual thread executed: method={}, time={}ms, activeThreads={}",joinPoint.getSignature().getName(),stopWatch.getTotalTimeMillis(),currentThreads);returnresult;}finally{activeVirtualThreads.decrementAndGet();}}}十三、启动类
packagecom.example.demo;importlombok.extern.slf4j.Slf4j;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.context.event.ApplicationReadyEvent;importorg.springframework.context.event.EventListener;@Slf4j@SpringBootApplicationpublicclassSpringBoot4MybatisPlusApplication{publicstaticvoidmain(String[]args){// 启用 AOT 优化System.setProperty("spring.aot.enabled","true");SpringApplication.run(SpringBoot4MybatisPlusApplication.class,args);}@EventListener(ApplicationReadyEvent.class)publicvoidonApplicationReady(){log.info("=========================================");log.info("Spring Boot 4.0 with MyBatis-Plus Started");log.info("Java Version: {}",System.getProperty("java.version"));log.info("Virtual Threads Available: {}",Thread.ofVirtual()!=null?"Yes":"No");log.info("Available Processors: {}",Runtime.getRuntime().availableProcessors());log.info("=========================================");}}十四、部署和优化
14.1 Dockerfile(支持原生镜像)
# 构建阶段 FROM ghcr.io/graalvm/native-image:java21 AS builder WORKDIR /app COPY target/*.jar app.jar RUN native-image -jar app.jar --no-fallback -H:Name=app-native # 运行阶段 FROM alpine:latest RUN apk add --no-cache libstdc++ WORKDIR /app COPY --from=builder /app/app-native /app/app EXPOSE 8080 ENTRYPOINT ["/app/app"]14.2 Docker Compose
version:'3.8'services:app:build:.ports:-"8080:8080"environment:-SPRING_PROFILES_ACTIVE=prod-JAVA_OPTS=-XX:+UseZGC-Xmx512mdepends_on:-mysqldeploy:resources:limits:memory:512Mmysql:image:mysql:8.0environment:MYSQL_ROOT_PASSWORD:123456MYSQL_DATABASE:mybatis_plus_demoports:-"3306:3306"volumes:-mysql_data:/var/lib/mysqlcommand:---default-authentication-plugin=mysql_native_password---character-set-server=utf8mb4---collation-server=utf8mb4_unicode_civolumes:mysql_data:十五、总结
15.1 关键特性使用
- 虚拟线程:通过
Thread.ofVirtual()和虚拟线程池优化并发性能 - 响应式编程:结合 MyBatis-Plus 和 R2DBC 实现非阻塞数据访问
- 结构化并发:使用 Java 21 的结构化并发 API
- AOT 编译:支持 GraalVM 原生镜像,提升启动速度
- 模块化:更好的 Java Module 支持
15.2 性能优化建议
- 对于 I/O 密集型操作,使用虚拟线程
- 对于高并发场景,使用响应式编程
- 使用 GraalVM 原生镜像减少内存占用和启动时间
- 合理配置连接池和线程池参数
15.3 整合事项
- Spring Boot 4.0 目前是预览版,API 可能会有变化
- 虚拟线程对阻塞操作敏感,避免在虚拟线程中执行长时间 CPU 操作
- 原生镜像编译需要处理反射和动态代理的注册
- 生产环境建议充分测试响应式和虚拟线程的稳定性
我的这个教程展示了如何利用 Spring Boot 4.0 的新特性(虚拟线程、响应式编程、AOT 编译等)来整合 MyBatis-Plus,构建高性能的现代 Java 应用程序。