为了说明@Configuration注解的作用,我们先来看一个maven创建的spring项目
// 启动类
public class MainTest {
@Test
public void TestMain(){
new AnnotationConfigApplicationContext(AppConfig.class);
}
}
// 配置类
@Configuration
public class AppConfig {
@Bean
public User user(){
return new User();
}
@Bean
public User2 user2() {
user();
return new User2();
}
}
// 两个实体类
public class User {
public User() {
System.out.println(“User对象”);
}
}
public class User2 {
public User2() {
System.out.println(“User2对象”);
}
}
这是一个最简单的spring项目,在配置类中有@Configuration注解,我们运行启动类,可以看到如下打印信息:
image-20210115101414931
如果去掉配置类中的@Configuration注解会怎样呢,去掉之后,咱们来看看打印信息:
image-20210115101618212
分析:
- 在上面的代码中,并没有直接调用配置类和实体类,说明这些都在spring底层进行了封装
- 在配置类中User类是进行了两次实例化的,但加了@Configuration注解后,只进行一次实例化,说明@Configuration注解将@Bean的方法进行的增强,保证实例为单实例
2. 问题
问1:@Configuration注解是如何定义bean之间的依赖关系?
问2:@Configuration注解是如何将@Bean方法进行增强的?
下面将跟踪spring源码来回答这两个问题
三、源码追踪
启动类代码只有AnnotationConfigApplicationContext
类,所以咱们以这里为入口,点进去可以看到源码如下:
public AnnotationConfigApplicationContext(Class<?>… componentClasses) {
this();
this.register(componentClasses);
this.refresh();
}
在这段源码中
-
this()
:这个无参构造是和bean相关的 -
register(componentClasses)
:将componentClasses注册到beanDefinitionMap集合中去 -
refresh()
:和@Configuration注解相关
所以咱们跟踪refresh()
,点进去查看源码:
【AbstractApplicationContext
类中refresh
方法】
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start(“spring.context.refresh”);
this.prepareRefresh();
// 告诉子类加载内部bean工厂
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 准备在上下文中使用的bean工厂
this.prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后置处理
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start(“spring.context.beans.post-process”);
// 这个方法是源码分析里面比较重要的一个入口,这里只讲和@Configuration注解相关的
// 解析@Configuration配置类,将自定义的BeanFactoryPostProcessor、BeanPostProcessor注册到beanDefinitionMap
this.invokeBe