Browse Source

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
pull/27107/head
Sam Brannen 5 years ago
parent
commit
2ec7d5c785
  1. 26
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
  2. 7
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java

26
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

@ -81,6 +81,7 @@ import org.springframework.util.ClassUtils;
* @author Chris Beams * @author Chris Beams
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Phillip Webb * @author Phillip Webb
* @author Sam Brannen
* @since 3.0 * @since 3.0
*/ */
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
@ -376,21 +377,30 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
for (String beanName : beanFactory.getBeanDefinitionNames()) { for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE); Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
AnnotationMetadata annotationMetadata = null;
MethodMetadata methodMetadata = null; MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) { 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) { if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method // 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; AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) { if (!abd.hasBeanClass()) {
try { boolean liteConfigurationCandidateWithoutBeanMethods =
abd.resolveBeanClass(this.beanClassLoader); (ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
} annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
catch (Throwable ex) { if (!liteConfigurationCandidateWithoutBeanMethods) {
throw new IllegalStateException( try {
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex); abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
} }
} }
} }

7
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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 Chris Beams
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen
* @since 3.1 * @since 3.1
*/ */
abstract class ConfigurationClassUtils { abstract class ConfigurationClassUtils {
@ -162,6 +163,10 @@ abstract class ConfigurationClassUtils {
} }
// Finally, let's look for @Bean methods... // Finally, let's look for @Bean methods...
return hasBeanMethods(metadata);
}
static boolean hasBeanMethods(AnnotationMetadata metadata) {
try { try {
return metadata.hasAnnotatedMethods(Bean.class.getName()); return metadata.hasAnnotatedMethods(Bean.class.getName());
} }

Loading…
Cancel
Save