{"record":{"id":"7e645d2ce9ff3311","repo":"spring-projects/spring-framework","slug":"aspect-class-aspectclass-getname-does-not-de","errorCode":null,"errorMessage":"Aspect class [{aspectClass.getName()}] does not define a singleton aspect","messagePattern":"Aspect class \\[(.+?)\\] does not define a singleton aspect","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectJProxyFactory.java","lineNumber":96,"sourceCode":"\t */\n\tpublic AspectJProxyFactory(Class<?>... interfaces) {\n\t\tsetInterfaces(interfaces);\n\t}\n\n\n\t/**\n\t * Add the supplied aspect instance to the chain. The type of the aspect instance\n\t * supplied must be a singleton aspect. True singleton lifecycle is not honored when\n\t * using this method - the caller is responsible for managing the lifecycle of any\n\t * aspects added in this way.\n\t * @param aspectInstance the AspectJ aspect instance\n\t */\n\tpublic void addAspect(Object aspectInstance) {\n\t\tClass<?> aspectClass = aspectInstance.getClass();\n\t\tString aspectName = aspectClass.getName();\n\t\tAspectMetadata am = createAspectMetadata(aspectClass, aspectName);\n\t\tif (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Aspect class [\" + aspectClass.getName() + \"] does not define a singleton aspect\");\n\t\t}\n\t\taddAdvisorsFromAspectInstanceFactory(\n\t\t\t\tnew SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));\n\t}\n\n\t/**\n\t * Add an aspect of the supplied type to the end of the advice chain.\n\t * @param aspectClass the AspectJ aspect class\n\t */\n\tpublic void addAspect(Class<?> aspectClass) {\n\t\tString aspectName = aspectClass.getName();\n\t\tAspectMetadata am = createAspectMetadata(aspectClass, aspectName);\n\t\tMetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);\n\t\taddAdvisorsFromAspectInstanceFactory(instanceFactory);\n\t}\n\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectJProxyFactory.java#L78-L114","documentation":"Thrown as an IllegalArgumentException from AspectJProxyFactory.addAspect(Object aspectInstance). This overload requires the supplied aspect INSTANCE to be a singleton aspect (per-clause kind SINGLETON), because Spring reuses that single instance across all advised targets. If the aspect class declares perthis/pertarget/pertypewithin/percflow semantics, a single shared instance is semantically invalid, so Spring rejects it.","triggerScenarios":"Calling new AspectJProxyFactory(target).addAspect(myAspectInstance) where myAspectInstance's class is annotated @Aspect(\"perthis(...)\"), @Aspect(\"pertarget(...)\"), @Aspect(\"pertypewithin(...)\"), or any non-singleton per-clause.","commonSituations":"Passing a pre-built aspect instance to AspectJProxyFactory when the aspect was designed for per-object instantiation; mixing programmatic proxy factory usage with aspects intended for container-managed prototype scope.","solutions":["Use the addAspect(Class) overload instead, which supports non-singleton aspects by creating independent instances via a factory.","Re-annotate the aspect as a plain @Aspect (singleton) if per-object state is not actually required.","Manage per-object state inside the singleton aspect using ThreadLocal or a keyed map rather than the perthis/pertarget model."],"exampleFix":"// before\n@Aspect(\"pertarget(execution(* com.example.Target.*(..)))\")\npublic class PerTargetAspect { ... }\n\nAspectJProxyFactory factory = new AspectJProxyFactory(target);\nfactory.addAspect(new PerTargetAspect()); // throws\n\n// after\nAspectJProxyFactory factory = new AspectJProxyFactory(target);\nfactory.addAspect(PerTargetAspect.class); // uses class-based overload","handlingStrategy":"validation","validationCode":"import org.aspectj.lang.reflect.AjTypeSystem;\nimport org.aspectj.lang.reflect.PerClauseKind;\n\npublic static boolean isSingletonAspect(Class<?> aspectClass) {\n    return AjTypeSystem.getAjType(aspectClass).getPerClause().getKind() == PerClauseKind.SINGLETON;\n}\n\n// before addAspect(instance):\nif (!isSingletonAspect(instance.getClass())) {\n    // use the class-based overload instead\n    factory.addAspect(instance.getClass());\n} else {\n    factory.addAspect(instance);\n}","typeGuard":"import org.aspectj.lang.reflect.AjTypeSystem;\nimport org.aspectj.lang.reflect.PerClauseKind;\n\npublic static boolean canAddAsInstance(Object aspectInstance) {\n    return AjTypeSystem.getAjType(aspectInstance.getClass())\n            .getPerClause().getKind() == PerClauseKind.SINGLETON;\n}","tryCatchPattern":"try {\n    factory.addAspect(aspectInstance);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage().contains(\"does not define a singleton aspect\")) {\n        factory.addAspect(aspectInstance.getClass()); // fallback to class-based\n    } else throw ex;\n}","preventionTips":["Use addAspect(Class) when unsure about the instantiation model; it handles both singleton and non-singleton aspects.","Reserve addAspect(Object instance) for singleton aspects whose lifecycle you manage externally.","Document the singleton-only contract of addAspect(Object) in code comments."],"tags":["spring-aop","aspectj","instantiation-model","programmatic-proxy"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}