这篇文章对 spring源码的分析仅仅相当于 “hello,world” 的程度。
Spring 的 ApplicationContext 是非常重要的,之前总是从大的层面来看,比如整体的架构;现在尝试从更微小的层面来研究,两者相结合,对 Spring 的了解会更深刻。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.springframework.context.annotation6");
context.refresh();
context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName()));
context.getBean("testBean"); // contributed by ConfigForScanning
context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName()));
context.getBean(uncapitalize(Jsr330NamedForScanning.class.getSimpleName()));
Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
assertEquals(1, beans.size());
来自 Spring 源码中的单元测试
初始化
调用 AnnotationConfigApplicationContext
构造函数时,执行以下代码:
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
官方文档给出解释,AnnotationConfigApplicationContext
需要调用 register()
来进行填充,并手动调用 refresh()
进行刷新。如此看来,应该有构造函数在指定了需要填充的内容后,自动完成填充以及刷新吧。果然,AnnotationConfigApplicationContext
还有着如下两个构造函数:
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
分析以上,可以发现,最终都会调用无参的构造函数,那么看来,AnnotatedBeanDefinitionReader
和 ClassPathBeanDefinitionScanner
非常重要了。
扫描
context.scan("org.springframework.context.annotation6")
调用的方法如下:
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
此处的 scanner
就是上面的 ClassPathBeanDefinitionScanner
:
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
第一个 scan()
并不会真正的去处理扫描逻辑,而是由 doScan()
所做的;注意到了嘛?doScan()
的访问控制修饰符变为了 protected
,如果需要拓展,Spring 建议我们重写该方法,Spring 在很多处都采用了这种暗示。这对于我们来说将非常方便。
上面方法的执行大概分为:
-
查找候选
bean
定义这里有个非常重要的类:
BeanDefiniition
(bean 定义),bean 定义描述了一个 bean 实例,属性值,构造函数参数值以及能够为具体实现该 bean 而提供的更多的信息。在这个阶段,仅仅是通过扫描给定的包,而获得的一个非常初始化的 bean定义,后续阶段,都是基于这些数据,进行再次处理,丰富了这个 bean 定义。 -
处理候选的
bean
定义2.1 设置 bean 定义的域的元数据
元数据为描述数据的数据
这一步根据 bean 定义解析出 bean 的域元数据。实际上就是为了将 bean 定义中的
@Scope
注解(如果存在的话)转换为ScopeMetadata
,重新存入 bean 定义中。@Bean @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) public TestBean testBean() { return new TestBean(); }
最初的候选 bean定义中,仅仅存储了注解的信息,但实际上这些注解信息的具体作用,则需要一步一步解析。
如何解析则
ScopeMetadataResolver
接口的实现类AnnotationScopeMetadataResolver
来解析:@Override public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { ScopeMetadata metadata = new ScopeMetadata(); if (definition instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition; AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor( annDef.getMetadata(), this.scopeAnnotationType); if (attributes != null) { metadata.setScopeName(attributes.getString("value")); ScopedProxyMode proxyMode = attributes.getEnum("proxyMode"); if (proxyMode == ScopedProxyMode.DEFAULT) { proxyMode = this.defaultProxyMode; } metadata.setScopedProxyMode(proxyMode); } } return metadata; }
ScopeMetadataResolver
接口被定义为策略接口(策略模式上线了)。查看该接口的实现类,发现还有一个Jsr330ScopeMetadataResolver
实现类,该实现类是处理基于javax.inject.Singleton
或javax.inject.Scope
的域注解的(不同于 spring 的规范,其实是一种东西)。
2.2 获取 bean 的名称
bean 名称的解析由
BeanNameGenerator
接口的实现类AnnotationBeanNameGenerator
来完成(该接口依然为策略接口)。bean 名称要么是根据我们所定义注解的 value 值取得,要么就是使用默认的 bean 名称,即通过 Class 转换,例如:“mypackage.MyJdbcDao" -> "myJdbcDao”。2.3 预处理 bean 定义
即为 bean定义是否能够延迟初始化附上默认值等
2.4 处理 bean 定义的通用注解
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } else if (abd.getMetadata() != metadata) { lazy = attributesFor(abd.getMetadata(), Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } } if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class); if (dependsOn != null) { abd.setDependsOn(dependsOn.getStringArray("value")); } AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); }
根据 bean 定义中的通用注解,重新为 bean 定义赋值。
2.5 bean 定义的域代理模式处理
2.6 注册 Bean 定义
刷新
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为刷新准备此上下文
prepareRefresh();
// 告诉子类刷新内部 bean 工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备 bean 工厂以供在此上下文中使用
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对 bean 工厂进行后期处理
postProcessBeanFactory(beanFactory);
// 调用上下文中注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 为此上下文初始化消息源。
initMessageSource();
// 为此上下文初始化事件多播程序。
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean。
onRefresh();
// 检查侦听器bean并注册它们
registerListeners();
// 实例化所有剩余的(非惰性初始化)单例。
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}