2.2.1 Bean的注册
在使用Spring时,我们可以通过获取一个应用上下文(ApplicationContext)对象来操作各种Bean,示例代码如代码清单2-9所示,相信你对这段代码不会陌生。
代码清单2-9 获取应用上下文对象的示例代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
这里的ApplicationContext接口代表的就是一个Spring IoC容器,而在Spring中存在一大批ApplicationContext接口的实现类。如果使用基于注解的配置方式,就可以使用上述代码中的AnnotationConfigApplicationContext来初始化容器上下文对象。
在刚开始阅读Spring源码时,我建议你直接从AnnotationConfigApplicationContext的启动流程切入,这一流程位于它的构造函数中,如代码清单2-10所示。
代码清单2-10 AnnotationConfigApplicationContext构造函数代码
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); //根据注解配置类注册Bean register(annotatedClasses); //刷新容器 refresh(); } public AnnotationConfigApplicationContext(String... basePackages) { this(); //根据包路径配置扫描Bean scan(basePackages); //刷新容器 refresh(); }
这两个构造函数的作用很明确,一个是根据注解配置类注册Bean,另一个则是根据包路径配置扫描Bean。这里我们以register()方法为例,来讨论Bean的注册过程,该方法如代码清单2-11所示。
代码清单2-11 AnnotationConfigApplicationContext的register()方法代码
public void register(Class<?>... annotatedClasses) { Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); this.reader.register(annotatedClasses); }
这里依赖AnnotatedBeanDefinitionReader工具类来完成Bean的注册。AnnotatedBean-DefinitionReader会遍历所有传入的annotatedClasses注解类,然后通过代码清单2-12所示的doRegisterBean()方法完成注册。(由于该方法的代码较长,我们对重要逻辑添加了注释,对不重要的代码做了省略。)
代码清单2-12 AnnotationConfigApplicationContext的doRegisterBean()方法代码
<T> void doRegisterBean(...) { //将注解配置类信息转换成一种BeanDefinition AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); … //获取Bean的作用域元数据,解析Bean作用域 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); //将Bean的作用域写回BeanDefinition abd.setScope(scopeMetadata.getScopeName()); //生成beanName String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); //解析AnnotatedBeanDefinitionReader中的@Lazy、@Primary等注解 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); //处理@Qualifier注解 if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { // 如果设置了@Primary注解,则设置当前Bean为首选Bean abd.setPrimary(true); } else if (Lazy.class == qualifier) { //如果设置了@Lazy注解,则设置当前Bean为延迟加载模式 abd.setLazyInit(true); } else { //其他注解,则添加到BeanDefinition中 abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } … //注册Bean对象 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
这段代码包含Bean注册过程中的三个核心步骤,如图2-1所示。
图2-1 AnnotatedBeanDefinitionReader中Bean注册的核心步骤示意图
首先,我们构建用来描述Bean实例信息的BeanDefinition对象,这需要将注解配置类信息转成AnnotatedGenericBeanDefinition数据结构,而AnnotatedGenericBeanDefinition就是一种BeanDefinition,包含了Bean的构造函数参数、各种属性值以及所添加的注解信息。
然后,我们设置BeanDefinition属性,这一步骤完成了对@Scope、@Primary、@Lazy等注解的处理。
最后,通过registerBeanDefinition()方法完成Bean的注册,该方法内部通过Listable-BeanFactory的实现类DefaultListableBeanFactory将Bean定义信息注册到Spring IoC容器中。ListableBeanFactory是Spring中常用的一个BeanFactory,通过这个接口,我们可以一次获取多个Bean。