1.

Spring「CGLIB is required to process @Configuration classes」の原因と対処

編集
この記事の要点
  • CGLIB is required は Spring が @Configuration クラスのプロキシ生成に必要な CGLIB を見つけられないエラー
  • Spring 4.x までは別途依存追加が必要、Spring 5+ では cglib-nodep が同梱だが依存除外時に発生
  • 対処A: cglib(または cglib-nodep)依存を追加
  • 対処B: @Configuration(proxyBeanMethods = false) で CGLIB プロキシ不要に(Spring 5.2+)
  • 対処C: 依存ツリーで cglib を除外している箇所 (exclusions) を探して削除
  • Spring Boot は通常問題なし、Spring Framework 単体 + 古い依存管理で出やすい

このエラーの概要

Spring アプリ起動時に次のスタックトレースで失敗します:

Caused by: java.lang.IllegalStateException: CGLIB is required to process
@Configuration classes. Either add CGLIB to the classpath or remove the
following @Configuration bean definitions:
[appConfig]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor
       .enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:434)

これは Spring が @Configuration クラスを「実体クラスのまま」ではなく CGLIB 動的サブクラスとして動かそうとしたとき、CGLIB が classpath に居ないと発生します。

なぜ CGLIB が必要か

Spring は @Configuration クラスの @Bean メソッド間呼び出し(inter-bean reference)を制御するために、クラスを CGLIB でサブクラス化してプロキシ化します:

@Configuration
public class AppConfig {

    @Bean
    public UserRepository userRepository() {
        return new UserRepository();
    }

    @Bean
    public UserService userService() {
        // ↓ この呼び出しが「都度 new UserRepository()」ではなく、
        //   Spring コンテナから既存のシングルトンを取得するように
        //   CGLIB プロキシによって書き換えられる
        return new UserService(userRepository());
    }
}

CGLIB が無いと、userRepository() 呼び出しが本当に都度 new されてしまい、シングルトンが崩れます。Spring はそれを許容せず起動時に止めます。

対処1: CGLIB 依存を追加(Spring 4 系 / 依存除外している場合)



    cglib
    cglib
    3.3.0




    cglib
    cglib-nodep
    3.3.0
// Gradle (build.gradle)
dependencies {
    implementation 'cglib:cglib:3.3.0'

    // または nodep 版
    implementation 'cglib:cglib-nodep:3.3.0'
}

対処2: proxyBeanMethods = false で CGLIB 不要に(Spring 5.2+)

inter-bean reference を使わないなら、CGLIB プロキシを完全に無効化できます:

// Spring 5.2 以降
@Configuration(proxyBeanMethods = false)
public class AppConfig {

    @Bean
    public UserRepository userRepository() {
        return new UserRepository();
    }

    @Bean
    public UserService userService(UserRepository repo) {
        // ↑ メソッド呼び出しではなく、引数注入で受け取る
        return new UserService(repo);
    }
}

これで CGLIB は不要、起動も高速化。GraalVM Native Image でも有利。Spring Boot 2.2+ の @SpringBootConfiguration も内部で proxyBeanMethods = false 推奨パターンを採用しています。

設定動作CGLIB起動時間
@Configuration(既定)フルプロキシ、メソッド呼び出しを intercept必要普通
@Configuration(proxyBeanMethods = false)軽量、メソッド呼び出しは普通の new不要速い
@Component同じく軽量、ただし @Bean メソッドは推奨されない不要速い

対処3: 依存除外を解除

誰かが exclusions で CGLIB / spring-core を除外している可能性があります:



    org.springframework
    spring-context
    
        
            cglib
            cglib
        
    

依存ツリーを調べる:

# Maven
mvn dependency:tree | grep -i cglib

# Gradle
./gradlew dependencies --configuration runtimeClasspath | grep -i cglib

# 結果に cglib が出てこなければ classpath に無い

対処4: ASM ライブラリの確認

CGLIB は ASM に依存します。cglib 通常版を使うときは ASM のバージョン衝突に注意:



    org.ow2.asm
    asm
    9.5




    cglib
    cglib-nodep
    3.3.0

Spring Boot の場合

Spring Boot 2.x+ では spring-boot-starterspring-core(内部に spring-asm + CGLIB 同等機能)を持っており、通常はこのエラーが出ません。出る場合は:

  1. 誰かが spring-core を除外している
  2. Java バージョンが古い(Java 8 未満で動かそうとした)
  3. クラスローダー分離が極端(OSGi 等)
# Boot プロジェクトで spring-core が解決されているか
./gradlew dependencies --configuration runtimeClasspath | grep spring-core

# org.springframework:spring-core:5.3.x ← これがあれば CGLIB 機能あり

関連: Final クラス問題

CGLIB は対象クラスをサブクラス化するため、final クラスや final メソッドだとプロキシ化できません:

// ❌ NG: final クラス
@Configuration
public final class AppConfig {  // ← Cannot subclass final class
    @Bean
    public Foo foo() { ... }
}

// ❌ NG: final メソッド
@Configuration
public class AppConfig {
    @Bean
    public final Foo foo() { ... }  // ← Cannot subclass final method
}

// ✅ OK: 普通のクラス・メソッド
@Configuration
public class AppConfig {
    @Bean
    public Foo foo() { ... }
}

Kotlin の class は既定で final なので、open class にするか kotlin-spring プラグインを使用:

// Kotlin
@Configuration
open class AppConfig {  // open 必須
    @Bean
    open fun foo(): Foo = Foo()
}

// または build.gradle.kts で
plugins {
    kotlin("plugin.spring") version "1.9.0"  // 自動 open
}

FAQ

Q: cglibcglib-nodep、どちら?
A: nodep 版が安全。ASM を内包しているので、プロジェクトの ASM とバージョン衝突しません。

Q: Spring 5+ なのに出る
A: 1) 誰かが spring-core を除外、2) Maven shade plugin で誤って削除、3) クラスローダー分離問題、を確認。

Q: GraalVM Native Image で起動できない
A: CGLIB は動的バイトコード生成に依存し、Native Image と相性が悪いです。@Configuration(proxyBeanMethods = false) または Spring Native (Spring Boot 3 + AOT) を使用。

関連エラー

  • Cannot subclass final class — 対象クラスが final、Kotlin の場合は open 必須
  • java.lang.NoClassDefFoundError: net/sf/cglib/proxy/Enhancer — CGLIB 自体が classpath に無い、対処1
  • NoSuchMethodError: org.springframework.asm.ClassVisitor — Spring と ASM のバージョン不整合
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. java.lang.IllegalStateException: CGLIB is required to process @Configuration classes
  2. Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
  3. No mapping found for HTTP request with URI ... in DispatcherServlet with name ...
  4. An internal error occurred during: "Building UI model". com/google/common/base/Function
  5. No identifier specified for entity : ...
  6. org.hibernate.hql.internal.ast.QuerySyntaxException: table_name is not mapped
  7. No compiler is provided in this environment
  8. java.sql.SQLException: The server time zone value ' ... ' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone
  9. Caused by: java.lang.RuntimeException: Executing an update/delete query
  10. Not supported for DML operations
  11. Field ... required a bean of type ... hat could not be found.
  12. Annotation-specified bean name ' ... ' for bean class [ ... ] conflicts with existing, non-compatible bean definition of same name and class [...]
  13. Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.
  14. Exception in thread "main" java.lang.UnsupportedClassVersionError