使用JavaConfig时,SpringBean定义类名为null

使用JavaConfig时,SpringBean定义类名为null,java,spring,spring-java-config,Java,Spring,Spring Java Config,我正在实现BeanFactoryPostProcessor,并试图提取bean定义类名: @Component public class MyFactory implements BeanFactoryPostProcessor{ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { String[] beanDe

我正在实现
BeanFactoryPostProcessor
,并试图提取bean定义类名:

@Component
public class MyFactory implements BeanFactoryPostProcessor{

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
    for (String name : beanDefinitionNames) {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);

        // 'null' when using JavaConfig, 'java.lang.String' when using XML
        System.out.println(beanDefinition.getBeanClassName());
    }

}

}
当我通过XML配置Bean时,我可以毫无问题地获得类名:

<bean id="arbitraryString" class="java.lang.String"/>

<bean class="com.test.MyFactory"/>

我尝试过搜索这个,但无法理解我是否做错了什么,或者这是预期的行为。在我的main方法中,除了加载上下文(无论是XML还是config类),我什么也不做。

我已经仔细研究了一下,我想我知道问题可能是什么(不确定我是否正确,或者我的解释是否正确)。然而,这似乎是一个问题:

在JavaConfig类中定义bean会导致spring初始化这个类。然而,这里的顺序很重要,我认为:

它将获取您的配置类,检索所有@Bean注释的方法,然后创建这些对象

现在我相信您所指的“根bean”是一个实现类,以防您实例化该类。这看起来很自然,但SpringXML和SpringJavaConfig之间有一个目标

在xml中:

所有bean都定义为类。它们通过调用该类的构造函数来实例化

在JavaConfig中:

bean不再是一个独立的bean。它被当作工厂生产的豆子。因此bean实际上没有根bean类,它有一个工厂bean和一个工厂方法。如何从方法定义中设置根类?您可以将根bean设置为类,但这在大多数类中并不成立。工厂可以返回返回的类的任何实现,因此在创建BeanDefinition对象时,没有可用的根bean

这可以通过将appconfig标记为static(工厂方法)来观察。现在,没有工厂bean,因为在扫描配置类时,它没有被创建。这意味着spring将使用CGI创建一个实现,即根bean。然而,这不是您所期望的根bean。例如,在我的测试中:

com.*.*.AppConfig$$EnhancerBySpringCGLIB$$1d5cc574
这是我在创建静态bean时得到的输出

因此,总的来说:

JavaConfig的作用类似于一个工厂,因此创建的bean在定义形成时是未知的

Xml定义良好,显式设置了实现类,因此给出了根bean

需要生成静态bean,因为工厂不存在,但仍然需要创建类

我希望这有帮助:)

--阿图尔


编辑:最后一点注意,它的预期行为:)

带有
@Bean
的Bean由
ConfigurationClassBeanDefinitionReader
和Bean定义 定义类是
AnnotatedBeanDefinition

所以。您可以从它的
FactoryMethodMetadata

if(beanDefinition instanceof AnnotatedBeanDefinition) { // definition with @Bean Annotation cause this issue
    MethodMetadata factoryMethodMetadata = ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata();
    if (factoryMethodMetadata != null) {
        className = factoryMethodMetadata.getReturnTypeName();
    }
}

您是否尝试在注释中提供Bean名称
@Bean(name=“arbirystring”)
的可能重复:这似乎是意料之中的behaviour@MichaelMurray刚刚尝试过,仍然为空。@pandadb这不是重复的,我确实发现了这个问题,但它没有解决在本例中使用JavaConfig和xml之间的区别。需要通过调用构造函数来创建配置。因此,很清楚实现bean是什么,因此(通过CGI增强)类是根bean。在我的例子中:appConfig:Root bean:class[com.*.*.appConfig$$EnhancerBySpringCGLIB$$1d5cc574]
if(beanDefinition instanceof AnnotatedBeanDefinition) { // definition with @Bean Annotation cause this issue
    MethodMetadata factoryMethodMetadata = ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata();
    if (factoryMethodMetadata != null) {
        className = factoryMethodMetadata.getReturnTypeName();
    }
}