简体   繁体   中英

Spring bean definition class name is null when using JavaConfig

I'm implementing BeanFactoryPostProcessor and I'm trying to extract the bean definitions class names:

@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());
    }

}

}

When I configure my beans via XML, I get the class name without any problem:

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

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

However, when I use JavaConfig and define a bean there (a simple String for demonstration purposes), the class name will be null:

@Bean 
public String arbitraryString () {
    return "the bean definition class name will be null";
}

I've tried searching this and couldn't understand if I'm doing something wrong or this is expected behavior. I'm doing nothing else in my main method but load the context (whether XML or config class).

I've looked into it a bit, and I think I know what the issue may be (not sure if I am right, or if I am explaining it right). However, this seems to be the issue:

Defining beans in your JavaConfig class causes initialisation of this class by spring. The order however here is important I think:

It will pick up your config class, retrieve all @Bean annotated methods and then create those objects.

Now I believe the "root bean" that you are referring to is an implementing class, in case you are instantiating the class. This seems naturally, but there is a destiction to be made between spring XML and spring javaconfig.

In xml:

All beans are defined as classes. They are instantiated by calling the Constructor of that class.

In JavaConfig:

The bean is no longer a standalone bean. It is treated as a factory bean. So the bean does not really have a root bean class, it has a factory bean and a factory method. How would you set the root class from the method definition? You can set the root bean to be the class, but that will not hold true in most classes. The factory can return any implementation of the returned class, so at the time of creating the BeanDefinition object, there is no root bean available.

This can be observed by marking your appconfig static (the factory methods). Now, there is no factory bean, because at the time the configuration class is scanned, it is not created. This means, that spring will use CGI to create an implementation which is the root bean. This however, is not the root bean, that you would expect. For example, in my test:

com.*.*.AppConfig$$EnhancerBySpringCGLIB$$1d5cc574

This is the output I get when creating static beans.

So in total:

JavaConfig acts like a factory, so the bean created is not known at the time the definition is formed.

Xml is well defined, the implementing class is explicitly set, so a root bean is given.

Static beans need to be generated, because the factory does not exist, but the class still needs to be created.

I hope that helps :)

-- Artur

Edit: Final note, it's expected behaviour :)

Bean with @Bean is defined by ConfigurationClassBeanDefinitionReader and bean definition class is AnnotatedBeanDefinition

So. You can get class name from it's FactoryMethodMetadata

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM