From 2ec7d5c78526e60f0d9c919bccccf75fbb1ebbb7 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 22 Feb 2021 09:59:15 +0100 Subject: [PATCH] Support load-time weaving for @Component classes again Since Spring Framework 5.2, the LoadTimeWeaver no longer weaves bean classes annotated with @Component. This is a regression caused by the changes in 40c62139ae, stemming from the fact that any class annotated or meta-annotated with @Component is considered to be a candidate configuration class in 'configuration lite' mode (i.e., a class without the @Configuration annotation and without any @Bean methods) and therefore now has its class eagerly loaded. This results in the class being loaded before the LoadTimeWeaver has a chance to weave it. This commit fixes this regression by explicitly avoiding eager class loading for any 'lite' @Configuration or @Component class without @Bean methods. Closes gh-26199 --- .../ConfigurationClassPostProcessor.java | 26 +++++++++++++------ .../annotation/ConfigurationClassUtils.java | 7 ++++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 515c78c91a3..ad6e2fab124 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -81,6 +81,7 @@ import org.springframework.util.ClassUtils; * @author Chris Beams * @author Juergen Hoeller * @author Phillip Webb + * @author Sam Brannen * @since 3.0 */ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, @@ -376,21 +377,30 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE); + AnnotationMetadata annotationMetadata = null; MethodMetadata methodMetadata = null; if (beanDef instanceof AnnotatedBeanDefinition) { - methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata(); + AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef; + annotationMetadata = annotatedBeanDefinition.getMetadata(); + methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata(); } if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) { // Configuration class (full or lite) or a configuration-derived @Bean method - // -> resolve bean class at this point... + // -> eagerly resolve bean class at this point, unless it's a 'lite' configuration + // or component class without @Bean methods. AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef; if (!abd.hasBeanClass()) { - try { - abd.resolveBeanClass(this.beanClassLoader); - } - catch (Throwable ex) { - throw new IllegalStateException( - "Cannot load configuration class: " + beanDef.getBeanClassName(), ex); + boolean liteConfigurationCandidateWithoutBeanMethods = + (ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) && + annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata)); + if (!liteConfigurationCandidateWithoutBeanMethods) { + try { + abd.resolveBeanClass(this.beanClassLoader); + } + catch (Throwable ex) { + throw new IllegalStateException( + "Cannot load configuration class: " + beanDef.getBeanClassName(), ex); + } } } } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java index 3758084c319..da377b13fd3 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,7 @@ import org.springframework.stereotype.Component; * * @author Chris Beams * @author Juergen Hoeller + * @author Sam Brannen * @since 3.1 */ abstract class ConfigurationClassUtils { @@ -162,6 +163,10 @@ abstract class ConfigurationClassUtils { } // Finally, let's look for @Bean methods... + return hasBeanMethods(metadata); + } + + static boolean hasBeanMethods(AnnotationMetadata metadata) { try { return metadata.hasAnnotatedMethods(Bean.class.getName()); }