Spring源码之BeanFactory和BeanDefinition
- BeanFactory和BeanDefinition
- BeanFactory
- BeanDefinition
- 源码分析
- 创建AnnotationConfigApplicationContext对象
- 注册配置类
- refresh方法
BeanFactory和BeanDefinition
BeanFactory
BeanFactory是Spring提供给外部访问容器的根接口,接口中包含了getBean等常见的方法;经常使用到的ApplicationContext就实现了BeanFactory接口。
BeanFactory的主要实现类如下:
- DefaultListableBeanFactory是最常用的 BeanFactory 实现之一,它是一个可列表的(listable)、可修改的(modifiable)Bean 工厂实现,支持 bean 的按名称查询、类型查询以及通过别名查询。它还支持 bean 定义的动态注册和修改。此实现类通常与 BeanDefinitionReader 配合使用,可以从 XML、注解或其他配置来源加载 Bean 定义
ApplicationContext主要实现类如下:
-
ClassPathXmlApplicationContext
- ClassPathXmlApplicationContext用于从类路径(classpath)中的XML配置文件加载上下文定义。适合那些配置文件位于类路径下的应用,它在启动时会读取指定的XML文件并初始化 Spring 容器
-
FileSystemXmlApplicationContext
- 从文件系统中的任何位置加载 XML 配置文件,需要提供文件系统的绝对路径
-
AnnotationConfigApplicationContext
- 用于通过注解配置的 Spring 应用程序。它不需要 XML 配置文件,而是通过扫描带有 @Configuration 和 @Component 等注解的类来发现和注册 Bean
-
AnnotationConfigWebApplicationContext
- 特定于 web 应用的上下文,它继承自 GenericApplicationContext 并提供了 web 应用特有的功能,如与 Servlet 上下文的集成。适用于基于注解的 Spring MVC 应用
- 除了AnnotationConfigWebApplicationContext,还存在一个类似的XmlWebApplicationContext,也是用于Web环境的
-
GenericApplicationContext
- GenericApplicationContext 不是一个直接用于生产环境的实现,但它提供了一个基础的上下文实现,可以被其他上下文实现类扩展。它不直接关联任何特定的配置机制,通常与其他 BeanDefinitionReader 一起使用来加载配置
我们在启动Spring Web应用时会使用WebContext去启动容器,创建Bean对象。非Web应用根据使用是注解还是配置文件去决定使用哪种类型的Context。
BeanDefinition
BeanDefinition中文翻译过来就是Bean定义,Spring会根据BeanDefinition去创建Bean,而BeanDefinition则在Spring容器启动的时候从配置文件或者根据注解去解析得到。
BeaDefinition继承了AttributeAccessor接口和BeanMetadataElement接口。
- AttributeAccessor接口提供了对BeanDefinition属性操作的能力
- BeanMetadataElement接口则可以返回Bean的来源
Spring提供了BeanDefinitionRegistry去操作BeanDefinition,BeanDefinitionRegistry接口具有增、删、查(这里的增删查指的是对存放BeanDefinition的集合进行操作)BeanDefinition的能力。
Spring同时也提供了一个BeanDefinitionReader接口,这个接口是用于从xml配置文件或者java配置文件中读取BeanDefinition的。
BeanDefinition的主要子类如下:
- AbstractBeanDefinition
- AbstractBeanDefinition统一实现了BeanDefinition定义的一部分操作,可以说是定义了BeanDefinition很多默认的属性。 正是在AbstractBeanDefinition基础上, Spring衍生出了一些列BeaDefinition
- AnnotatedBeanDefinition
- 表示注解类型BeanDefinition。有两个重要的属性,AnnotationMetadata,MethodMetadata分别表示BeanDefinition的注解元信息和方法元信息 实现了此接口的BeanDefinition可以获取到注解元数据和方法元数据
- AnnotatedGenericBeanDefinition
- 表示@Configuration注解注释的BeanDefinition类
- ScannedGenericBeanDefinition
- 表示@Component、@Service、@Controller等注解注释的Bean类
- RootBeanDefinition
- 代表一个xml文件或者java配置文件的BeanDefinition
源码分析
public class MainStart {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);String[] definitionNames = context.getBeanDefinitionNames();for (String definitionName : definitionNames) {System.out.println("definitionName:" + definitionName);}}
}
创建AnnotationConfigApplicationContext对象
首先是创建AnnotationConfigApplicationContext对象
会在父类的构造函数中创建出BeanFactory对象
在构造函数中会创建AnnotatedBeanDefinitionReader实例对象和ClassPathBeanDefinitionScanner实例对象;AnnotatedBeanDefinitionReader用于通过注解获取BeanDefinitin,ClassPathBeanDefinitionScanner则是通过扫描路径下的包和类获取BeanDefinitin
在创建AnnotatedBeanDefinitionReader实例对象的过程中,会注册一些Spring运行所需要的后置处理器
- 设置@AutoWired的候选的解析器:ContextAnnotationAutowireCandidateResolver
getLazyResolutionProxyIfNecessary方法,它也是唯一实现。 - 如果字段上带有@Lazy注解,表示进行懒加载 Spring不会立即创建注入属性的实例,而是生成代理对象,来代替实例
注册解析配置类的后置处理器ConfigurationClassPostProcessor
注册处理@Autowired 注解的处理器AutowiredAnnotationBeanPostProcessor
注册处理JSR规范的注解处理器CommonAnnotationBeanPostProcessor
处理jpa注解的处理器org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
处理监听方法的注解@EventListener解析器EventListenerMethodProcessor
注册事件监听器工厂
最后会调用registerPostProcessor将指定的类注册为BeanDefinition,调用过程如下:
注册配置类
在doRegisterBean方法中,首先根据配置类创建出了对应的AnnotatedGenericBeanDefinition对象
然后判断是否需要跳过注解,spring中有一个@Condition注解,当不满足条件,这个bean就不会被解析
解析bean的作用域,如果没有设置的话,默认为单例
解析注解,填充到AnnotatedGenericBeanDefinition,解析的注解为Lazy,Primary,DependsOn,Role,Description
注册BeanDefinition
验证BeanDefinition是否合法
判断BeanDefinition是否已经存在,这里是第一次注册所以为false
把BeanDefinition加入到BeanDefinition map中
到这里注册BeanDefinition的过程就结束了。
refresh方法
通过上面的debug,目前已经知道了Spring怎么注册 配置类以及Processor的BeanDefinition,那么配置类中通过@Bean注解注册的Bean的BeanDefinition是在怎么时候注册的呢?答案是在refresh方法中进行注册的
refresh方法中有一个invokeBeanFactoryPostProcessors方法
loadBeanDefinitionsForConfigurationClass方法就是用于从配置类中加载BeanDefinition的
从使用@Bean注解标记的方法中获取对应的BeanDefinition
获取通过@ImportResources注解和ImportBeanDefinition加载进来的BeanDefinition
到这里加载BeaDefinition的过程就结束了,所有的BeanDefinition就已经注册完成了。