spring既支持xml式配置bean,也可以通过@Configuration注解来配置bean,xml是spring最初支持的方式,随着springboot的出现,通过@Configuration注解来配置bean也越来越被采用,常见的配置如下:
@Configuration
public class TestConfig {
protected static Logger logger = LoggerFactory.getLogger(TestConfig.class);
public TestConfig(){
logger.info("TestConfig创建");
}
@Bean("student")
Student student(){
logger.info("student创建");
return new Student(address());
}
@Bean
Address address(){
logger.info("address创建");
return new Address();
}
}
那么@Configuration注解到底背后的工作原理是什么呢,笔者将从源码角度引入讲述@Configuration注解的工作原理,下面简单概述下Configuration注解是被初始化的流程:
AbstractApplicationContext::refresh-->AbstractApplicationContext::invokeBeanFactoryPostProcessors
-->ConfigurationClassPostProcessor::postProcessBeanFactory-->ConfigurationClassPostProcessor::enhanceConfigurationClasses
ConfigurationClassPostProcessor::enhanceConfigurationClasses这个方法是Configuration注解工作的核心方法,spring应用启动时所有的被@Configuration注解的类都会被spring cglib库生成cglib动态代理,然后其他地方通过@Autowired注解引入Student类对象就会被生成的configuration配置类生成的动态代理拦截,处理完后再调用原configuration注解类的student方法获取到Student实例。
Configuration注解类初始化的过程我们知道了,那么在Configuration注解内的@Bean注解的方法又是如何被调用的呢,不着急,下面我们将随着源码的探究揭开这层面纱。
@Bean注解方法被调用的入口就在AbstractAutowireCapableBeanFactory::createBeanInstance方法上,下面贴出核心代码:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
由于@Bean注解方法生成的Bean实例getFactoryMethodName不为null,所以就会通过调用对应的bean方法来创建该Bean实例!
想要了解更多的可以在调试spring项目时进入对应源码跟踪调试。