前一篇文章 BeanFactory 体系结构 中,就 BeanFactory 接口的继承关系、基本的方法定义做了描述,并未对其实现类 DefaultListableBeanFactory 以及 XmlBeanFactory 的代码做分析。
在实际应用中,使用到的 Spring Ioc 容器多是 ApplicationContext 接口的实现类,最常用的几个实现类为:
- ClassPathXmlApplicationContext(基于 xml 配置文件的 Ioc 容器),
- AnnotationConfigApplicationContext(基于注解的 Ioc 容器),
- XmlWebApplicationContext(web应用中基于 xml 文件的 Ioc 容器)
从本篇文章开始,将从 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 类开始分析 Spring Ioc 容器实现的源码。
ApplicationContext 体系结构
从 ApplicationContext 体系结构图分析整理类继承关系如下:
ApplicationContext
WebApplicationContext
ConfigurableWebApplicationContext
ConfigurableApplicationContext
AbstractApplicationContext
AbstractRefreshableApplicationContext
AbstractRefreshableConfigApplicationContext
-- ClasspathXmlApplicationContext
AbstractRefreshableWebApplicationContext
-- XmlWebApplicationContext
GenericApplicationContext
-- AnnotationConfigApplicationContext
ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 源码分析
-
ClassPathXmlApplicationContext 构造函数
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); // 设置配置文件 setConfigLocations(configLocations); if (refresh) { // 1. 核心方法 refresh(); } }
- super(parent)
调用父类 AbstractApplicationContext 的构造函数, 主要包含两部分:
创建了一个 ResourceLoader 实例,这个 ResourceLoader 就是 AbstractApplicationContext
-
设置父容器,上述初始化方式下父容器为 null
public AbstractApplicationContext(@Nullable ApplicationContext parent) { this(); setParent(parent); } public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); } protected ResourcePatternResolver getResourcePatternResolver() { return new PathMatchingResourcePatternResolver(this); }
- setConfigLocations(configLocations)
setConfigLocations主要工作有两个:创建环境对象ConfigurableEnvironment 、处理ClassPathXmlApplicationContext传入的字符串中的占位符;
- 环境对象ConfigurableEnvironment中包含了当前JVM的profile配置信息、环境变量、 Java进程变量;
- 处理占位符的关键是ConfigurableEnvironment、PropertyResolver、PropertyPlaceholderHelper之间的配合:
public void setConfigLocations(@Nullable String... locations) { if (locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { // 核心代码 this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } } // AbstractRefreshableConfigApplicationContext::resolvePath protected String resolvePath(String path) { return getEnvironment().resolveRequiredPlaceholders(path); } // AbstractApplicationContext::getEnvironment public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment; } // AbstractApplicationContext::createEnvironment protected ConfigurableEnvironment createEnvironment() { return new StandardEnvironment(); } // AbstractPropertyResolver::resolveRequiredPlaceholders public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException { if (this.strictHelper == null) { this.strictHelper = createPlaceholderHelper(false); } return doResolvePlaceholders(text, this.strictHelper); }
- super(parent)
-
AnnotationConfigApplicationContext 构造函数
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); register(annotatedClasses); refresh(); }
AnnotationConfigApplicationContext 类继承了 GenericApplicationContext 类,因此当调用 AnnotationConfigApplicationContext 的构造函数时,会默认先调用父类 GenericApplicationContext 的无参构造函数。从具体的代码中可知,在 GenericApplicationContext 的无参构造函数中初始化成员变量 beanFactory 为 DefaultListableBeanFactory。
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
- this()
从源码中可以看到,在AnnotationConfigApplicationContext的无参构造函数中会初始化 reader(基于注解的 BeanDefinition 读取器) 和 scanner(类路径的 BeanDefinition 扫描器)
public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
- register(annotatedClasses)
public void register(Class<?>... annotatedClasses) { Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); this.reader.register(annotatedClasses); } public void register(Class<?>... annotatedClasses) { for (Class<?> annotatedClass : annotatedClasses) { registerBean(annotatedClass); } } public void registerBean(Class<?> annotatedClass) { doRegisterBean(annotatedClass, null, null, null); } <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); //@Conditional装配条件判断是否需要跳过注册 if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(instanceSupplier); //解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); //生成bean配置类beanName String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); //通用注解解析到abd结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); // @Qualifier特殊限定符处理 if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { // 如果配置@Primary注解,则设置当前Bean为自动装配autowire时首选bean if (Primary.class == qualifier) { abd.setPrimary(true); } //设置当前bean为延迟加载 else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { //其他注解,则添加到abd结构中 abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } for (BeanDefinitionCustomizer customizer : definitionCustomizers) { customizer.customize(abd); } //根据beanName和bean定义信息封装一个beanhold,heanhold其实就是一个 beanname和BeanDefinition的映射 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // BeanDefinitionReaderUtils.registerBeanDefinition 内部通过DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)按名称将bean定义信息注册到容器中 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
- this()
总结
本篇文章介绍了 ApplicationContext 体系图,以及简要分析了 ClasspathXmlApplicationContext 和 AnnotationConfigApplicationContext 构造函数中的前两个方法,其中涉及到的一些类以及类的作用如下:
-
ClasspathXmlApplicationContext
类名 作用 ConfigurableEnvironment 1.创建PropertyResolver; 2.向PropertyResolver提供环境变量、 Java进程变量 PropertyResolver 1.创建PropertyPlaceholderHelper; 2.定义占位符的前缀和后缀(placeholderPrefix、placeholderSuffix); 3.提供getPropertyAsRawString方法给PropertyPlaceholderHelper调用,用来获取指定key对应的环境变量 PropertyPlaceholderHelper 1.找到字符串中的占位符;2.调用PropertyResolver.getPropertyAsRawString方法,从环境变量中取出占位符对应的值;3.用环境变量的值替换占位符 AnnotationConfigApplicationContext
在构造函数的 refresh 函数之前,首先创建了 BeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner 对象,然后创建配置类本身的 BeanDefinition 信息并注册到 BeanFactory 中。
分析完 ClasspathXmlApplicationContext 和 AnnotationConfigApplicationContext 构造函数中的前两个方法后,后续的文章将继续分析最核心的方法 refresh。