在《Spring-IOC容器原理之启动过程》一文中讲到,负责BeanDefinition加载过程都封装在模板方法loadBeanDefinitions(beanFactory);中,下面就以AnnotationConfigWebApplicationContext的这个较为复杂的容器实现,从这个方法为起点,开始BeanDefinition加载过程的分析之旅。
BeanDefinition的加载过程
直接上源码:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 使用的BeanDefinitionReader是AnnotatedBeanDefinitionReader
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
// 使用ClassPathBeanDefinitionScanner去扫描指定package下的BeanDefinition,并注册到容器
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// BeanNameGenerator定义了BeanName生成策略
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
// ScopeMetadataResolver用于解析@Scope注解
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.annotatedClasses.isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}
//AnnotatedBeanDefinitionReader加载带有BeanDefinition注解的类
reader.register(this.annotatedClasses.toArray(new Class<?>[this.annotatedClasses.size()]));
}
if (!this.basePackages.isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// ClassPathBeanDefinitionScanner扫描指定package下的类文件
scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
}
// 对configLocations配置的处理,优先使用AnnotatedBeanDefinitionReader去解析,
// 解析失败将使用ClassPathBeanDefinitionScanner去解析
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = getClassLoader().loadClass(configLocation);
if (logger.isInfoEnabled()) {
logger.info("Successfully resolved class for [" + configLocation + "]");
}
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not load class for config location [" + configLocation +
"] - trying package scan. " + ex);
}
int count = scanner.scan(configLocation);
if (logger.isInfoEnabled()) {
if (count == 0) {
logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
}
else {
logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
}
}
}
}
}
}
从以上源码可以看出,实现BeanDefinition加载的类有两个:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。
AnnotatedBeanDefinitionReader通过解析类信息来加载BeanDefinition,这些类是BeanDefinition配置的载体,可能带有一些BeanDefinition相关的注解,如@Configuration,@Bean等,甚至没有任何注解,这时加载的将是最普通的BeanDefinition,它将通过构造函数完成实例化(请参考Spring-IOC容器原理之Bean创建过程)。
ClassPathBeanDefinitionScanner通过扫描指定package下的class文件,把满足筛选条件的class作为BeanDefinition配置的载体,并把class信息转换为BeanDefinition后,注册到容器。
下面分别看看这两个类的实现。
AnnotatedBeanDefinitionReader实现
AnnotatedBeanDefinitionReader的核心方法是registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers):
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
// 创建BeanDefinition,这里的实现类是AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// conditionEvaluator用于获取@Conditional注解中配置的Condition实例,
// 并通过Condition判断该类是否满足条件约束,只有满足条件约束,才能对其进行解析
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 解析@Scope注解,解析出ScopeName和ScopeProxyMode
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 配置BeanDefinition的scope
abd.setScope(scopeMetadata.getScopeName());
// beanName生成
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 完成通用注解的配置
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// ScopeProxyMode不是ScopeProxyMode.NO的时候
// 对BeanDefinition进行增强,
// 使用ScopeProxyFactoryBean作为实现类,用于生成一个代理Bean
// 该代理Bean主要增加ScopedObject接口的实现,
// 代理委派给DefaultScopedObject来完成
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//向容器注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
在这里,向容器注册的BeanDefinition的具体实现是AnnotatedGenericBeanDefinition,它继承了GenericBeanDefinition,并在GenericBeanDefinition的基础上新增了AnnotatedBeanDefinition接口的实现:
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
* @return the annotation metadata object (never {@code null})
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
* @return the factory method metadata, or {@code null} if none
* @since 4.1.1
*/
MethodMetadata getFactoryMethodMetadata();
}
由于这里我们使用class类信息作为BeanDefinition配置的载体,因此class中的注解元数据,类型信息,方法名称等信息都应该能成为BeanDefinition配置的一部分,这些元数据信息通过AnnotationMetadata和MethodMetadata来表达,正如AnnotatedBeanDefinition接口声明所示。这种接口扩展真是顺势而为啊!
AnnotationMetadata和MethodMetadata这两个接口很重要,可以说是解析BeanDefinition配置的基础数据。下面分别看看这两个接口的定义:
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
//获取class上所有标注的类型名称
Set<String> getAnnotationTypes();
//获取class上名字为annotationName的标注类型名称,包括标注上的其他标注
Set<String> getMetaAnnotationTypes(String annotationName);
//判断class上是否有标注名称为annotationName的标注
boolean hasAnnotation(String annotationName);
//判断class上是否有标注名称为annotationName的标注,包括标注上的其他标注
boolean hasMetaAnnotation(String metaAnnotationName);
//判断class中是否带有标注的方法
boolean hasAnnotatedMethods(String annotationName);
//获取带有指定标注名称annotationName的方法元数据
Set<MethodMetadata> getAnnotatedMethods(String annotationName);
}
AnnotationMetadata定义了解析class上的注解相关方法。另外,AnnotationMetadata继承了ClassMetadata和AnnotatedTypeMetadata接口:
public interface ClassMetadata {
String getClassName();
boolean isInterface();
boolean isAnnotation();
boolean isAbstract();
boolean isConcrete();
boolean isFinal();
boolean isIndependent();
boolean hasEnclosingClass();
String getEnclosingClassName();
boolean hasSuperClass();
String getSuperClassName();
String[] getInterfaceNames();
String[] getMemberClassNames();
}
public interface AnnotatedTypeMetadata {
boolean isAnnotated(String annotationName);
Map<String, Object> getAnnotationAttributes(String annotationName);
Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
}
从ClassMetadata和AnnotatedTypeMetadata接口声明中可以看出,ClassMetadata定义了与class定义相关信息的获取接口,而AnnotatedTypeMetadata则定义了通用可注解元素(类/属性/方法)对注解的通用获取接口。
最后,MethodMetadata则定义了与方法定义相关信息的获取接口:
public interface MethodMetadata extends AnnotatedTypeMetadata {
String getMethodName();
String getDeclaringClassName();
String getReturnTypeName();
boolean isAbstract();
boolean isStatic();
boolean isFinal();
boolean isOverridable();
}
由此可见,AnnotatedGenericBeanDefinition已经具备了所有用于从class中读取所有BeanDefinition配置元数据的功能了,这为后面通过元数据生成BeanDefinition提供了数据基础。
接下来可以看到,所有分析配置过程都依赖于ClassMetadata和AnnotatedTypeMetadata元数据。
接着是conditionEvaluator.shouldSkip(),该方法用于获取@Conditional注解中配置的Condition实例,并通过Condition判断该BeanDefintion是否满足约束条件,这个过程并不复杂,具体实现可参考源代码。
AnnotationConfigUtils.processCommonDefinitionAnnotations()方法就是对一般注解的处理了,包括@Lazy/@Primary/@DependsOn/@Role/@Description注解。
最后则调用BeanDefinitionReaderUtils.registerBeanDefinition()向容器注册BeanDefinition了。到此,AnnotatedBeanDefinitionReader的register()方法也就执行完成了。
ClassPathBeanDefinitionScanner实现
ClassPathBeanDefinitionScanner的核心方法是scan(String... basePackages):
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);
}
doScan()方法中实现了核心逻辑:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (String basePackage : basePackages) {
// 找出候选的BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 这里的过程与AnnotatedBeanDefinitionReader.registerBean()异常相似了
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;
}
可以看到,doScan()的实现与AnnotatedBeanDefinitionReader.registerBean()异常相似了,不同的是,在doScan()中需要实现查找候选的BeanDefinition的功能,这在父类ClassPathScanningCandidateComponentProvider.findCandidateComponents()方法中实现:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
findCandidateComponents()的实现有以下几个关键步骤:
- PathMatchingResourcePatternResolver找到package下的所有class文件,并以Resource返回。
- 需要一个解析器,把Resource解析为AnnotationMetadata,这由MetadataReader来完成
- 分析AnnotationMetadata元数据,找出满足筛选条件的AnnotationMetadata,默认的筛选条件是类定义中含有@Component注解
- 将AnnotationMetadata封装成ScannedGenericBeanDefinition作为候选BeanDefinition
@Service/@Repository/@Configuration注解定义上都添加了@Component注解的,因此这里扫描出来的类自然包括了这些注解所标注的类了。
这个过程涉及几个重要的类型,下面简单说明一下它们的特性,至于这些类的实现原理请自行翻阅源码。
- PathMatchingResourcePatternResolver可以按给定的路径模式找到对应的资源Resource列表
- MetadataReader可以解析基于Resource的class文件为AnnotationMetadata,解析过程是基于ASM框架。
- ScannedGenericBeanDefinition与AnnotatedGenericBeanDefinition的实现类似,只是并没有实现MethodMetadata
至此,AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的核心实现已经分析完了。但相信读者可以发现,这个过程非常简单,似乎少了一些注解的实现,比如@ComponentScan,@Bean等等,那么这些注解的处理是在哪里实现的呢?其实这是在一个BeanDefinitionRegistryPostProcessor实现中处理的,这个BeanDefinitionRegistryPostProcessor实现类是ConfigurationClassPostProcessor。
那这个ConfigurationClassPostProcessor又是在哪里注册进容器的呢?其实在AnnotatedBeanDefinitionReader的构造函数及ClassPathBeanDefinitionScanner的scan()方法中都有这个后处理器的注册调用。如以下代码清单:
//AnnotatedBeanDefinitionReader的构造函数
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// 这里就是注册ConfigurationClassPostProcessor的入口了
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
// ClassPathBeanDefinitionScanner的scan()方法实现
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// 这里就是注册ConfigurationClassPostProcessor的入口了
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
//AnnotationConfigUtils.registerAnnotationConfigProcessors()
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//在这里看到ConfigurationClassPostProcessor的注册了
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
在AnnotationConfigUtils.registerAnnotationConfigProcessors()中,除了注册了ConfigurationClassPostProcessor后处理器,还有其他一些常用的后处理器在《Spring-IOC容器原理之Bean创建过程》中有介绍过了。
ConfigurationClassPostProcessor
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,根据《Spring-IOC容器原理之启动过程》中关于容器启动过程的说明,容器会先进行postProcessBeanDefinitionRegistry()方法的回调,接着回调BeanFactoryPostProcessor接口。因此,我们先看ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()的实现:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 注册了ImportAwareBeanPostProcessor后处理器,完成对ImportAware接口的注入
RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
// 注册了EnhancedConfigurationBeanPostProcessor后处理器,完成对EnhancedConfiguration的处理
RootBeanDefinition ecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME, ecbpp);
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
// 这里是处理配置类的核心入口
processConfigBeanDefinitions(registry);
}
在此处,注册了两个后处理器ImportAwareBeanPostProcessor和EnhancedConfigurationBeanPostProcessor,分别用于完成对ImportAware接口的注入以及对EnhancedConfiguration的处理。之后processConfigBeanDefinitions()调用对容器中注册的BeanDefinition进行解析处理,以找到更多隐藏在配置类中BeanDefinition,并把这些BeanDefinition注册到容器中去。
processConfigBeanDefinitions()的处理可以分解为如下图所示的三个过程,这三个过程循环执行,直至再也找不到未处理的ConfigurationBeanDefinition:

上图中包含了几个新的概念:
- ConfigurationBeanDefinition是指这样的BeanDefinition,它的class使用了@Configuration,@Component,@ComponentScan,@Import,@ImportResource注解,或者带有@Bean注解方法。ConfigurationBeanDefinition这个概念是自创的,只在本文中使用到,创造这个概念的原因是为了能更简单明了地表达这种类型的BeanDefinition。
- ConfigurationClass,是Spring中定义的一个类,一个ConfigurationClass对应着一个ConfigurationBeanDefinition,它表达了它是一个配置类的概念。ConfigurationClass用于存储解析ConfigurationBeanDefinition的中间结果(这个解析过程还是依赖于最基础的元数据AnnotationMetadata),这些中间解析结果包括@Bean注解的方法列表、通过@Import注解导入的ImportBeanDefinitionRegistrar列表、通过@ImportResource注解导入的BeanDefinition配置资源列表,以及ConfigurationClass是被哪些ConfigurationClass通过@Import导入进来的。这些中间解析结果是为了生成新的BeanDefinition做准备的。
- ConfigurationClassParser,也是Spring中定义的一个类,它的作用是把ConfigurationBeanDefinition解析成为ConfigurationClass。下面会详细讲解这些解析过程。
- ConfigurationClassBeanDefinitionReader,是Spring中定义的类,用于读取ConfigurationClass的中间解析结果,生成供容器使用的BeanDefinition,并注册到容器。
相信大家在认识了这四个新概念之后,对Spring是如何实现对ConfigurationBeanDefinition解析处理有了一个概念性的理解了,大家是否会觉得这种概念性的分析过程会更易记忆和理解呢?相信大家的回答都是YES!YES!YES!这就是挖掘高层次抽象性概念的好处了,让我们可以站在更高的高度去看待问题,会使我们的视野更开阔更明朗,而不至于出现“盲人摸象”的囧况。
有了高层次概念性理解之后,我们就可以深入到细节中去,深入探索内部奥秘,而不至于迷失方向。下面就先分析一下ConfigurationClassParser是如何解析ConfigurationBeanDefinition的。
ConfigurationClassParser解析ConfigurationBeanDefinition的过程封装在parse()方法中,然而核心的解析过程是在processConfigurationClass(ConfigurationClass)中进行,此时的入参ConfigurationClass已经封装了基础的元数据AnnotationMetadata,后续的解析过程是围绕AnnotationMetadata元数据进行的。而至于AnnotationMetadata是如何生成的呢?看看三个parse()的重载方法:
protected final void parse(String className, String beanName) throws IOException {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
可以看出,AnnotationMetadata的生成有三种方式,一种是ConfigurationBeanDefinition中已经含有AnnotationMetadata了,如AnnotatedGenericBeanDefinition,可以直接拿来使用,另一种是使用StandardAnnotationMetadata(Class)构造函数创建AnnotationMetadata,最后则直接通过MetadataReader(实现类是SimpleMetadataReader)解析class文件生成,这种方式的实现基于ASM框架,有兴趣的读者自行深入分析。
下面将关注点回到核心解析过程processConfigurationClass(ConfigurationClass)中来:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 对@Conditional注解中定义的Condition进行条件判断,判断通过才需要进行解析
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
// 对ConfigurationClass重复解析的处理
// 处理逻辑:
// 只保留不是通过@Import进来的ConfigurationClass的解析结果;
// 如果重复解析的ConfigurationClass都是通过@Import进来的,只需维护导入关系
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
}
// SourceClass是对AnnotationMetadata的另一种封装形式
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
// configClass描述的是一个ConfigurationBeanDefinition的配置类,而sourceClass描述的可能是configClass自身,也可能是configClass的父类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//记录下已经解析的ConfigurationClass
this.configurationClasses.put(configClass, configClass);
}
从以上源码可以看出,这里还未深入到AnnotationMetadata中去解析,而只是对ConfigurationClass进行@Conditional注解的条件判断,以及重复解析ConfigurationClass的处理逻辑:
- 只保留不是通过@Import进来的ConfigurationClass的解析结果
- 如果重复解析的ConfigurationClass都是通过@Import进来的,只需记录下被哪个ConfigurationClass导入进来的
其后循环调用doProcessConfigurationClass(configClass, sourceClass),以解析配置类的各继承层级,每个继承层级所对应的AnnotationMetadata,用SourceClass来表达,直至父类并不是java自身的类。doProcessConfigurationClass(configClass, sourceClass)的过程用以下活动图来表达其实现原理:

如图中黑色加粗方框所示,doProcessConfigurationClass()可以分解为以下子过程:解析内部类 -> 解析@PropertySource注解 -> 解析@ComponentScan注解 -> 解析@Import注解 -> 解析@ImportResource注解 -> 解析@Bean注解 -> 递归doProcessConfigurationClass()处理父类。每个方框内都表达了每个子过程的实现原理,理解了上图就理解了解析ConfigurationBeanDefinition的原理了。
在上图中,有一个比较唐突的新概念:importStack。它是一个ImportRegistry接口的实现类,它主要用于注册import关系的以及关系的获取,即ConfigurationClass是被哪个ConfigurationClass导入进来的。
从上图中也可以看出,在整个过程中,除了在解析@ComponentScan注解的过程中会向容器注册新的BeanDefinition之外,其他过程并没有向容器注册新的BeanDefinition。向容器注册新的BeanDefinition是交由ConfigurationClassBeanDefinitionReader完成的。
另外也应注意到,通过@Import导入以及解析内部类而得到的ConfigurationClass,并没有在容器中注册成BeanDefinition的形式。
ConfigurationClassBeanDefinitionReader
在上面的分析中,ConfigurationClassPostProcessor已经完成了对ConfigurationBeanDefinition的预解析,解析结果保存在ConfigurationClass中。下面看看ConfigurationClassBeanDefinitionReader是如何读取ConfigurationClass中的中间解析结果,完成BeanDefinition的生成和注册的。
ConfigurationClassBeanDefinitionReader读取ConfigurationClass的核心方法是loadBeanDefinitionsForConfigurationClass:
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
// trackedConditionEvaluator与conditionEvaluator类似,只不过
// trackedConditionEvaluator是对整个导入链进行条件约束校验,而非单
// 而非单个ConfigurationClass
if (trackedConditionEvaluator.shouldSkip(configClass)) {
// 当确定要跳过对configClass的处理之后,要从容器中移出注册的BeanDefinition
// 还要从importRegistry移除注册
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 如果configClass是通过Import进来的,还需要把它作为BeanDefinition
// 注册到容器中
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 把BeanMethod解析为BeanDefinition的处理过程,后续详解
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 处理@ImportResource解析的中间结果,调用BeanDefinitionReader加载BeanDefintion配置的地方
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//回调ImportBeanDefinitionRegistrar的接口完成BeanDefinition的注册
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
从以上源码中看到,上述过程并不复杂。
trackedConditionEvaluator用于校验configClass的导入方ConfigurationClass,甚至导入方的导入方ConfigurationClass,直到导入方并不是通过其他导入方导入,校验这整个导入链是否都满足条件约束,只有都满足的时候才需要继续处理。当导入链不满足条件约束时,将从容器中移除它的BeanDefinition,而且还需要从导入关系注册ImportRegistry中移除。
registerBeanDefinitionForImportedConfigurationClass()完成的是对import进来的configClass注册到容器中去,过程与AnnotatedBeanDefinitionReader.registerBean()非常类似,这里不再罗嗦。
loadBeanDefinitionsForBeanMethod()则是把BeanMethod解析为BeanDefinition的处理过程,如代码清单所示:
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
//这里还需要对BeanMethod上的Condition进行条件约束校验
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// Consider name and any aliases
// 从BeanMethod中解析出beanName以及aliase
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
String beanName = (names.size() > 0 ? names.remove(0) : methodName);
// Register aliases even when overridden
// 注册aliases
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// 判断容器中是否存在重复的BeanDefintion,存在着跳过
// Has this effectively been overridden before (e.g. via XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
return;
}
// 下面就开始创建BeanDefinition了
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
// @Bean注解的创建的Bean是使用工厂方法创建的,
// 这里就是确定使用的是静态工厂方法还是动态工厂方法,
// 以及工厂方法的名称
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
// 默认使用AUTOWIRE_CONSTRUCTOR的方式完成依赖注入
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
// 从BeanMethod中解析出初始化方法
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
// 从BeanMethod中解析出销毁方法
String destroyMethodName = bean.getString("destroyMethod");
if (destroyMethodName != null) {
beanDef.setDestroyMethodName(destroyMethodName);
}
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getAliasedString("value", Scope.class, configClass.getResource()));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
// 向容器中注册Bean定义
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
上述过程也是很简单明了的,若有不理解,通过中文的注释也应该能明白的,这里不再细致说明了。
其后loadBeanDefinitionsFromImportedResources()则是处理@ImportResource解析的中间结果的,实现方式就是调用BeanDefinitionReader加载BeanDefintion了,这里的BeanDefinitionReader可能是XmlBeanDefinitionReader,也可能是GroovyBeanDefinitionReader,甚至是自定义的BeanDefinitionReader。但默认情况是根据配置文件的后缀来决定使用XmlBeanDefinitionReader还是GroovyBeanDefinitionReader。
loadBeanDefinitionsFromRegistrars()就更简单了,只是回调ImportBeanDefinitionRegistrar的接口完成BeanDefinition的注册。
至此,关于ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()的实现已经解析完毕了。但ConfigurationClassPostProcessor还实现了postProcessBeanFactory()接口,下面不妨也看看这个接口的实现吧。
ConfigurationClassPostProcessor.postProcessBeanFactory()
直接上postProcessBeanFactory()接口实现:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
}
在上面源码中,比较陌生的是enhanceConfigurationClasses()方法实现,其目的是使用CGLIB代理加强使用了@Configuration注解的BeanDefinition,在其原来的基础上实现了EnhancedConfiguration接口,EnhancedConfiguration接口只是实现BeanFactoryAware接口而已。
在EnhancedConfigurationBeanPostProcessor后处理器中看到对EnhancedConfiguration接口的处理:
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
// postProcessPropertyValues method attempts to auto-wire other configuration beans.
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
至此,AnnotationConfigWebApplicationContext对BeanDefinition加载原理已经分析完毕,你是否已经掌握了呢?