You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Micronaut+GraalVM Native(AWS Lambda部署)集成MyBatis后GraalVM镜像运行时出现Javassist缺失错误

Micronaut+GraalVM Native(AWS Lambda部署)集成MyBatis后GraalVM镜像运行时出现Javassist缺失错误

我之前在类似的技术栈组合下也踩过这个坑:本地JVM运行一切正常,但打包成GraalVM原生镜像部署到Lambda就抛出Cannot enable lazy loading because Javassist is not available的错误。核心原因是GraalVM原生镜像采用AOT(提前编译)模式,不支持运行时动态生成字节码的工具(比如Javassist),而MyBatis默认依赖Javassist来生成Mapper接口的动态代理实现。

下面是我验证有效的解决方案,分步骤说明:

1. 替换MyBatis的动态代理方式为JDK代理

MyBatis支持两种代理实现:Javassist(默认)和JDK动态代理。我们可以修改MyBatis配置,强制使用JDK代理,彻底摆脱对Javassist的依赖。

修改你的MybatisFactory类,在构建Configuration后添加JDK代理的配置:

@Factory
class MybatisFactory(private val dataSource: DataSource) {
    @Singleton
    fun sqlSessionFactory(): SqlSessionFactory {
        val transactionFactory = ManagedTransactionFactory()
        val environment = Environment("micronaut", transactionFactory, dataSource)
        val configuration = Configuration(environment)
        // 关键:强制切换为JDK动态代理,替代默认的Javassist
        configuration.useJdkProxy = true
        configuration.addMappers(BASE_PACKAGE)
        return SqlSessionFactoryBuilder().build(configuration)
    }

    companion object {
        private const val BASE_PACKAGE = "com.foo.bar"
    }
}

2. 配置GraalVM原生镜像的元数据(反射/代理)

GraalVM提前编译时无法自动识别MyBatis Mapper接口的反射调用和代理需求,我们需要手动添加元数据配置,让GraalVM知道这些类需要被反射访问、允许生成代理。

在项目src/main/resources/META-INF/native-image/com.foo.bar/reflect-config.json(路径根据你的项目groupId调整)中添加以下配置(以MyMapper为例):

[
  {
    "name": "com.foo.bar.MyMapper",
    "allDeclaredMethods": true,
    "allPublicMethods": true,
    "methods": [
      {
        "name": "findById",
        "parameterTypes": ["int"]
      },
      {
        "name": "insert",
        "parameterTypes": ["com.foo.bar.MyModel"]
      }
    ]
  },
  {
    "name": "com.foo.bar.MyModel",
    "allDeclaredFields": true,
    "allPublicFields": true,
    "allDeclaredMethods": true,
    "allPublicMethods": true
  }
]

这个配置告诉GraalVM:MyMapper接口的方法需要被反射调用,MyModel实体类的字段和方法需要被MyBatis反射操作。如果有多个Mapper接口,需要为每个Mapper添加类似配置,也可以借助Micronaut的原生镜像插件自动扫描生成部分元数据。

3. 适配事务与Session的绑定逻辑

你使用了ManagedTransactionFactory配合Spring-TX的@Transactional,在GraalVM下需要确保事务上下文能正确绑定到MyBatis的Session,避免每次调用都新开独立Session导致事务失效。调整MapperExecutor的逻辑:

@Singleton
class MapperExecutor(private val sqlSessionFactory: SqlSessionFactory) {
    fun <T, R> execute(mapperClass: Class<T>, block: (T) -> R): R {
        // 优先从事务上下文获取绑定的Session,无事务时再新开Session
        val session = TransactionSynchronizationManager.getResource(sqlSessionFactory) as? SqlSession
            ?: sqlSessionFactory.openSession()
        return try {
            val mapper = session.getMapper(mapperClass)
            block(mapper)
        } finally {
            // 仅当Session未绑定事务时才手动关闭
            if (!TransactionSynchronizationManager.isActualTransactionActive()) {
                session.close()
            }
        }
    }
}

4. 依赖检查与调整

确保项目依赖中没有显式引入Javassist(如有可直接移除),同时添加Micronaut和MyBatis的GraalVM支持依赖,以Gradle为例:

implementation("io.micronaut.sql:micronaut-jdbc-hikari")
implementation("org.mybatis:mybatis:3.5.13")
implementation("org.springframework:spring-tx:6.0.15")
// Micronaut原生镜像运行时支持
runtimeOnly("io.micronaut:micronaut-runtime-native-image")

最后验证

修改完成后重新构建GraalVM原生镜像:

# Gradle项目
./gradlew nativeCompile
# Maven项目
./mvnw package -Dpackaging=native-image

部署到AWS Lambda测试后,Javassist相关的错误应该就会消失了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:09:33