1Bean のクラス名を出してみる
から取り出した に getClass().getName() を尋ねた出力です。の対象でない PlainService は元ののままですが、対象のを持つ ReportService は別のクラスになっていて、そのが元の ReportService です。を実装した GreeterImpl も、 の既定では同じ形になりました(末尾の数字は環境で変わる連番です)。
spring.aop.proxy-target-class = (not set)PlainService : l13.proxy.PlainServicesuperclass=java.lang.Object jdkProxy=false (AopUtils: aop=false jdk=false cglib=false)ReportService: l13.proxy.ReportService$$SpringCGLIB$$0superclass=l13.proxy.ReportService jdkProxy=false (AopUtils: aop=true jdk=false cglib=true)greeterImpl : l13.proxy.GreeterImpl$$SpringCGLIB$$0superclass=l13.proxy.GreeterImpl jdkProxy=false (AopUtils: aop=true jdk=false cglib=true)instanceof Greeter=true instanceof GreeterImpl=true
2サブクラス型の代理を手で書く
が実行時に生成するものを、手書きのサブクラスで真似た形です。利用側の変数の型は ReportService のままで、中身だけが代理になっています。外から呼ぶと代理を通りますが、本物の outer の中の this.inner() は本物に対する呼び出しなので、inner の前後には何も出ません。真似ているのは呼び出しの通り道だけで、本物はクラスを実行時に生成し、リファレンスによれば代理のを という仕組みで作ります(を2回呼ばないため)。
3設定を変えると JDK の動的プロキシになる
起動時に --spring.aop.proxy-target-class=false を付けた場合の出力です。インターフェースを実装した GreeterImpl の Bean は $Proxy56 という形の名前の になり、Greeter ではあっても GreeterImpl ではなくなりました。インターフェースの無い ReportService は、false にしても CGLIB のままです。
spring.aop.proxy-target-class = falsePlainService : l13.proxy.PlainServicesuperclass=java.lang.Object jdkProxy=false (AopUtils: aop=false jdk=false cglib=false)ReportService: l13.proxy.ReportService$$SpringCGLIB$$0superclass=l13.proxy.ReportService jdkProxy=false (AopUtils: aop=true jdk=false cglib=true)greeterImpl : l13.proxy.$Proxy56superclass=java.lang.reflect.Proxy jdkProxy=true (AopUtils: aop=true jdk=true cglib=false)instanceof Greeter=true instanceof GreeterImpl=false
4うまくいかない場合: final メソッド
を付けたメソッドはサブクラスで上書きできないので、代理は割り込めません。起動時に WARN が出るだけで起動はしますが、呼ぶとアドバイスは走らず、 name が null と表示されました。本体が代理のインスタンスの上で動き、代理の側のフィールドは初期化されていないためで、final でない normal() では field-value と出ています(この書き方での観測です)。
2026-10-01T13:21:41.725Z WARN 1 --- [ main] o.s.aop.framework.CglibAopProxy : Public final method [public final void l13.proxy.FinalMethodService.sealed()] cannot get proxied via CGLIB, consider removing the final marker or using interface-based JDK proxies....--- final methodFinalMethodService: l13.proxy.FinalMethodService$$SpringCGLIB$$0superclass=l13.proxy.FinalMethodService jdkProxy=false (AopUtils: aop=true jdk=false cglib=true)[advice] before normalnormal(): name = field-value[advice] after normalsealed(): name = null, this = FinalMethodService$$SpringCGLIB$$0
// l13/proxy/ProxyApp.java(抜粋)
@Component
class FinalMethodService {
private final String name = new String("field-value");
@Logged
public void normal() { System.out.println(" normal(): name = " + name); }
@Logged
public final void sealed() { System.out.println(" sealed(): name = " + name + ", this = " + this.getClass().getSimpleName()); }
}
5うまくいかない場合: final クラス
クラスそのものに final を付けると、サブクラスを作れないので代理を生成できず、起動に失敗しました(終了コード 1)。下はそのときの WARN 行で、原因の候補として final クラスと、見えないクラスの2つを挙げています。 のリファレンスにも、final クラスはできないのでにできないとあります。
2026-10-01T13:21:50.795Z WARN 1 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sealedService' defined in file [/work/aop/target/classes/l13/finalclass/SealedService.class]: Could not generate CGLIB subclass of class l13.finalclass.SealedService: Common causes of this problem include using a final class or a non-visible class
// l13/finalclass/FinalClassApp.java(抜粋)
@Component
final class SealedService { // final なのでサブクラスを作れない
@Logged
public void work() {}
}