Issue Description: When using the @ConditionalOnClass annotation, if there are multiple beans in the configuration class and the bean that is conditionally constrained does not exist at runtime, it causes other beans in the configuration class to fail initialization.
Steps to Reproduce:
- Create a configuration class (e.g., ClassNotFoundConfig) that contains a bean constrained by @ConditionalOnClass annotation and other beans.
- When the constrained class (e.g., DruidDataSource) does not exist in the runtime environment, other beans fail to initialize.
Expected Result: Other beans in the configuration class should be able to initialize successfully, even if the constrained class does not exist at runtime.
Solution:
- Avoid using Java reflection to obtain bean instances. Instead, use bytecode manipulation techniques.
- In the Spring source code, consider using ReflectionUtils.getUniqueDeclaredMethods() method to retrieve unique declared methods, rather than using getMethods() method from Java reflection.
- When computing the candidate methods, take into account the number of parameters and exclude methods with mismatched parameter counts.
Code Example:
@Configuration
public class ClassNotFoundConfig {
@Bean
public ExistingClass existingClass() {
return new ExistingClass();
}
@Bean(name = "sparrow_default")
@ConditionalOnClass(DruidDataSource.class)
public DruidDataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
问题描述: 在使用@ConditionalOnClass注解时,如果配置类中存在被条件约束的Bean,但该Bean的类在运行时不存在,会导致配置类中的其他Bean无法初始化。
问题复现步骤:
- 创建一个配置类(如ClassNotFoundConfig),其中包含被@ConditionalOnClass注解约束的Bean和其他Bean。
- 当运行时环境中不存在被约束的类(如DruidDataSource)时,其他Bean无法初始化。
预期结果: 配置类中的其他Bean应该能够正常初始化,即使被约束的类在运行时不存在。
解决方案:
- 避免使用Java反射机制获取Bean实例,可以使用字节码的形式来解决问题。
- 在Spring源码中,可以通过ReflectionUtils.getUniqueDeclaredMethods()方法获取唯一的声明方法,而不是使用Java反射的getMethods()方法。
- 在计算候选方法时,可以考虑参数数量,并排除参数数量不匹配的方法。
以下是代码示例:
@Configuration
public class ClassNotFoundConfig {
@Bean
public ExistingClass existingClass() {
return new ExistingClass();
}
@Bean(name = "sparrow_default")
@ConditionalOnClass(DruidDataSource.class)
public DruidDataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
Comment From: snicoll
@1921216468 do you work with @780886 by any chance? If that is the case, please stop creating duplicate issues for something that has been declined twice already.
If not, see https://github.com/spring-projects/spring-framework/issues/30563 and the issue it links to.
Comment From: leeezw
oh I'm sorry, I sincerely apologize. I wasn't aware that it had been declined twice already. Next time, I will make sure to browse the issue list first to ensure that no one has already raised it.