spring之ConfigurationClassPostProcessor
源码解析
文章目录
- spring之`ConfigurationClassPostProcessor`源码解析
- 1 用途
- 2 `postProcessBeanDefinitionRegistry`
- 2.1 检查`beanDef`是否是一个配置类(`full`或`lite`)
- 2.2 创建`ConfigurationClassParser`用来解析配置类
- 2.3 解析所有配置类
- 2.3.1递归处理内部类
- 2.3.2处理`@PropertySource`注解
- 2.3.3处理`@ComponentScan`注解
- 2.3.4处理`@Import`注解
- 2.3.5处理`@ImportResource`注解
- 2.3.6处理`@Bean`注解
- 2.3.7如果有父类,返回当前配置类的父类重复处理流程
- 2.3.8延迟处理`@Import`注解导入的`DeferredImportSelector`
- 2.4校验所有解析好的配置类
- 2.5使用`ConfigurationClassBeanDefinitionReader`加载`ConfigurationClass`中的`BeanDefinition`
- 3`postProcessBeanFactory`
1 用途
解析配置类
我们先来看一下这个类的类图
很明显,这个类是一个BeanFactoryPostProcessor
(BeanFactory增强器
),它会在容器中其它bean(普通bean,所有的BeanPostProcessor
等)创建之前实例化并执行。
2 postProcessBeanDefinitionRegistry
这个BeanFactoryPostProcessor
实例化后,首先会执行BeanDefinitionRegistryPostProcessor
接口的postProcessBeanDefinitionRegistry
,我们来看一下这个方法做了啥
/**
* Derive further bean definitions from the configuration classes in the registry.
* 从registry的配置类中获得更多的BeanDefinition
* 实际上就是解析registry中所有的配置类
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
/*********************检查是否处理过这个BeanDefinitionRegistry******************/
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);
/*********************************************************************/
//解析BeanDefinitionRegistry中配置类
processConfigBeanDefinitions(registry);
}
解析BeanDefinitionRegistry
中配置类
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//获取当前BeanDefinitionRegistry中所有bean的名字
String[] candidateNames = registry.getBeanDefinitionNames();
/*********************************************************************/
/**
* 遍历,找出BeanDefinitionRegistry中所有且未被解析过配置类
*/
for (String beanName : candidateNames) {
//根据名字获取对应的BeanDefinition
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
/**
* 已经解析过的BeanDefinition中会有这么一个Attribute(就是一个字符串,
* 作为标记,表示该类是一个配置类)
* String CONFIGURATION_CLASS_ATTRIBUTE =Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
*/
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//2.1检查beanDef是否是一个配置类(full或lite)
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
//找不到新的配置类,直接返回
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
//排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
/**
* 判断BeanName的生成策略,默认为false
* 默认情况下,componentScan生成BeanName是短类名
* 而@Import注解导入的类是完全限定名
*/
if (!this.localBeanNameGeneratorSet) {
/**
* AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR=
* "org.springframework.context.annotation.
* internalConfigurationBeanNameGenerator"
* 调用getSingleton方法从spring三级缓存中拿
* ,现在当然是拿不到的,对象还没创建呢,generator为null
*/
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
//private BeanNameGenerator componentScanBeanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
//private BeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
//环境不存在就创建一个标准环境
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
/*******************************解析配置类******************************/
// Parse each @Configuration class
//2.2创建ConfigurationClassParser用来解析配置类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//2.3解析所有配置类
parser.parse(candidates);
//2.4校验所有解析好的配置类
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//2.5使用ConfigurationClassBeanDefinitionReader加载ConfigurationClass中的BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
/**
* registerSingleton()将一个对象保存到spring的单例对象池中
* parser.getImportRegistry()就是获取ConfigurationClassParser中importStack属性对象
* importStack中保存了@Import注解导入的类的完全限定名和来源类的AnnotationMetadata,见2.3.4.3
*/
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
//清空工厂缓存,里面缓存了很多类的MetadataReader
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
2.1 检查beanDef
是否是一个配置类(full
或lite
)
/**
* Check whether the given bean definition is a candidate for a configuration class
* (or a nested component class declared within a configuration/component class,
* to be auto-registered as well), and mark it accordingly.
* @param beanDef the bean definition to check
* @param metadataReaderFactory the current factory in use by the caller
* @return whether the candidate qualifies as (any kind of) configuration class
*/
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
//bean的完全限定名
String className = beanDef.getBeanClassName();
//工厂类肯定不是配置类
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
AnnotationMetadata metadata;
/**
* spring中component-scan扫描@Component、@Configuration等类
* 形成ScannedGenericBeanDefinition,实现了AnnotatedBeanDefinition接口,
* 代表注解配置的bean
* 而xml配置文件配置的普通的bean标签形成的是GenericBeanDefinition
*/
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
/**
* className.equals(((AnnotatedBeanDefinition)beanDef).getMetadata().getClassName())
* 判定成功表明此时BeanDefinition中的metadata和BeanDefinition是匹配的,可以重用
*
* ScannedGenericBeanDefinition的metadata类型为SimpleAnnotationMetadata
*/
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
/**
* 2.1.1判断这个BeanDefinition对应的类是否已经被加载到jvm
* hasBeanClass()主要就是这个方法,
* 它判断BeanDefinition中beanClass属性是类名(未加载到jvm)还是clazz对象(已加载到jvm)
*/
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
/**
* BeanFactoryPostProcessor
* BeanPostProcessor
* AopInfrastructureBean
* EventListenerFactory
* 这四种类型的bean也不是配置类
*/
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
//创建StandardAnnotationMetadata,实际上就是使用简单反射来获取AnnotationMetadata
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
try {
/**
* 2.1.2使用metadataReaderFactory获取对应类的MetadataReader
* 再通过MetadataReader得到AnnotationMetadata
*
* 通过ASM来获取AnnotationMetadata
*/
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
//获取@Configuration注解的所有属性
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
/**
* proxyBeanMethods是@Configuration注解的一个属性
* 默认值为true,表示创建当前类的代理类,这样做的好处就是:可以拦截@Bean注解的方法,
* 当你在当前类中使用@Bean注解的方法获取对象的时候,不管调用多少次,返回的都是同一个对象
*/
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
//将配置类标识设置为full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
/**
* 2.1.3检测当前类中是否包含其他配置注解
* Component
* ComponentScan
* Import
* ImportResource
* Bean
*/
else if (config != null || isConfigurationCandidate(metadata)) {
//将配置类标识设置为lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
//非配置类
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
/**
* 2.1.4获取当前类中@Order注解的信息
* 主要是为了获取配置类的执行顺序
* 也是设置到BeanDefinition中
*/
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
2.1.1判断BeanDefinition
对应的类是否已经被加载
/**
* Return whether this definition specifies a bean class.
* @see #getBeanClass()
* @see #setBeanClass(Class)
* @see #resolveBeanClass(ClassLoader)
*/
public boolean hasBeanClass() {
return (this.beanClass instanceof Class);
}
这个方法比较简单,就是判断
beanClass
是不是一个clazz
,如果是clazz
,就代表BeanDefinition
对应的类是否已经被加载到jvm
了,那么此时就直接使用简单反射了,否则的话,beanClass
就是对应类的类名,此时要获取类注解的信息就只有两种方法:(1)通过
ClassUtils.forName("完全限定名")
,将该类加载到虚拟机, 然后使用简单反射获取类中的注解信息。(2)第二种方式就复杂了,通过
io
和ASM
直接操作字节码文件而不需要加载到jvm
中,与之对应的就是2.1.2
的内容了。
2.1.2使用metadataReaderFactory
获取对应类的MetadataReader
,然后得到AnnotationMetadata
metadataReaderFactory
是ConfigurationClassPostProcessor
类的属性,有默认值
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
但是你不要受这个迷惑,实际上用的并不是这个,而是
aware
接口方法调用创建的那个
public void setResourceLoader(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
if (!this.setMetadataReaderFactoryCalled) {
//这里重新new了一个MetadataReaderFactory,并传入了当前的resourceLoader
//而resourceLoader就是ApplicationContext
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
}
}
我们看一下
CachingMetadataReaderFactory
的getMetadataReader
方法
public MetadataReader getMetadataReader(String className) throws IOException {
try {
/**
* 拼接前类似于cn.lx.spring.v1.Config
* ResourceLoader.CLASSPATH_URL_PREFIX="classpath:"
* ClassUtils.CLASS_FILE_SUFFIX=".class"
* 就是当前类的字节码文件路径
*/
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
//通过路径获取字节码文件的统一资源描述
Resource resource = this.resourceLoader.getResource(resourcePath);
//获取MetadataReader
return getMetadataReader(resource);
}
catch (FileNotFoundException ex) {
// Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here...
// ClassUtils.forName has an equivalent check for resolution into Class references later on.
int lastDotIndex = className.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName =
className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);
String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;
Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
if (innerClassResource.exists()) {
return getMetadataReader(innerClassResource);
}
}
throw ex;
}
}
/**
* 获取MetadataReader
* @param resource 统一资源描述
*/
public MetadataReader getMetadataReader(Resource resource) throws IOException {
//判断当前这个MetadataReader缓存是不是一个线程安全的map
if (this.metadataReaderCache instanceof ConcurrentMap) {
// No synchronization necessary...
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
//父类getMetadataReader方法创建一个MetadataReader
metadataReader = super.getMetadataReader(resource);
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
//非线程安全的map就上锁,流程都差不多
else if (this.metadataReaderCache != null) {
synchronized (this.metadataReaderCache) {
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
metadataReader = super.getMetadataReader(resource);
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
}
else {
return super.getMetadataReader(resource);
}
}
去
CachingMetadataReaderFactory
父类的getMetadataReader
方法
public MetadataReader getMetadataReader(Resource resource) throws IOException {
//使用统一资源描述和类加载器初始化一个SimpleMetadataReader
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
至于说由
SimpleMetadataReader
得到AnnotationMetadata
的原理,这里就不在看了,你只需要知道它使用了ASM
就行了(ASM
框架可以直接操作(修改,添加方法和属性等)字节码文件)。
2.1.3检测当前类中是否包含其他配置注解
/**
* Check the given metadata for a configuration class candidate
* (or nested component class declared within a configuration/component class).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be registered for
* configuration class processing; {@code false} otherwise
*/
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
//当前类肯定不能是一个接口或注解
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
/**
* candidateIndicators.add(Component.class.getName());
* candidateIndicators.add(ComponentScan.class.getName());
* candidateIndicators.add(Import.class.getName());
* candidateIndicators.add(ImportResource.class.getName());
* 有这4个注解,表明是一个lite配置类
*/
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
try {
//判断当前类中包不包含有@Bean注解的方法
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
}
return false;
}
}
总结:只要类中有这5个注解(
@Component
,@ComponentScan
,@ImportResource
,@Import
,@Configuration
、@Bean
)之一,就表明该类是一个配置类。
2.1.4获取当前类中@Order
注解的信息
/**
* Determine the order for the given configuration class metadata.
* @param metadata the metadata of the annotated class
* @return the {@code @Order} annotation value on the configuration class,
* or {@code Ordered.LOWEST_PRECEDENCE} if none declared
* @since 5.0
*/
@Nullable
public static Integer getOrder(AnnotationMetadata metadata) {
//获取@Order注解的信息
Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
//AnnotationUtils.VALUE="value"
return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
}
2.2 创建ConfigurationClassParser
用来解析配置类
/**
* Create a new {@link ConfigurationClassParser} instance that will be used
* to populate the set of configuration classes.
*/
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
//上面用到过的MetadataReaderFactory,可以用来获取某个类的MetadataReader,最终获取到该类的注解信息
this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
/**
* 创建了一个ComponentScanAnnotationParser(解析@ComponentScan注解)
* componentScanBeanNameGenerator:默认短类名
*/
this.componentScanParser = new ComponentScanAnnotationParser(
environment, resourceLoader, componentScanBeanNameGenerator, registry);
//处理@Conditional注解
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
2.3 解析所有配置类
public void parse(Set<BeanDefinitionHolder> configCandidates) {
//遍历
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//已经解析过了,直接获取AnnotationMetadata
if (bd instanceof AnnotatedBeanDefinition) {
//解析某一个配置类
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
/**
* 简单反射获取AnnotationMetadata
* hasBeanClass()判断是否被加载到jvm中
*/
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//解析某一个配置类
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
//ASM获取AnnotationMetadata
else {
//解析某一个配置类
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//2.3.8延迟处理@Import注解导入的DeferredImportSelector
this.deferredImportSelectorHandler.process();
}
解析某一个配置类
parse
方法,有两个重载版本
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
}
protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}
再来看看
ConfigurationClass
的三个构造方法
/**
* Create a new {@link ConfigurationClass} with the given name.
* @param metadata the metadata for the underlying class to represent
* @param beanName name of the {@code @Configuration} class bean
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
//已经有了直接赋值
this.metadata = metadata;
//根据类名获取Resource(spring统一资源描述)
this.resource = new DescriptiveResource(metadata.getClassName());
this.beanName = beanName;
}
/**
* Create a new {@link ConfigurationClass} with the given name.
* @param clazz the underlying {@link Class} to represent
* @param beanName name of the {@code @Configuration} class bean
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(Class<?> clazz, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
/**
* 使用该方法获取clazz的AnnotationMetadata
* StandardAnnotationMetadata.from(clazz)
*
* 简单反射获取AnnotationMetadata
*/
this.metadata = AnnotationMetadata.introspect(clazz);
//根据类名获取Resource(spring统一资源描述)
this.resource = new DescriptiveResource(clazz.getName());
this.beanName = beanName;
}
/**
* Create a new {@link ConfigurationClass} with the given name.
* @param metadataReader reader used to parse the underlying {@link Class}
* @param beanName must not be {@code null}
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(MetadataReader metadataReader, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
//ASM获取AnnotationMetadata
//使用MetadataReader获取AnnotationMetadata(注解元数据)
this.metadata = metadataReader.getAnnotationMetadata();
//使用MetadataReader获取Resource(spring统一资源描述)
this.resource = metadataReader.getResource();
this.beanName = beanName;
}
从上面我们可以看到,三个构造方法最终都是为了计算出
ConfigurationClass
对象中AnnotationMetadata
、resource
、beanName
,而不同的是:对于AnnotatedBeanDefinition
类型的BeanDefinition
,它的AnnotationMetadata
是已经被解析过的,可以直接拿出来使用,而另外两种则是根据对应类是否被加载到jvm
中来分别进行处理的。三个
parse
方法都是先生成ConfigurationClass
对象(就代表了一个配置类,里面包含配置类的注解信息、统一资源描述和完全限定名),然后以它为参数调用processConfigurationClass
方法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
//@Conditional注解条件判断
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//已经解析过的配置类会放入缓存中
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
/**
* 当前类是被另一个配置类导入的
* ConfigurationClass中有一个属性Set<ConfigurationClass> importedBy
* 该属性记录了当前类是被哪个配置类导入的,见2.3.1
*
*/
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);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
//递归处理配置类和它的超类
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//处理配置类
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//缓存解析好的配置类
this.configurationClasses.put(configClass, configClass);
}
处理配置类
/**
* Apply processing and build a complete {@link ConfigurationClass} by reading the
* annotations, members and methods from the source class. This method can be called
* multiple times as relevant sources are discovered.
* @param configClass the configuration class being build
* @param sourceClass a source class
* @return the superclass, or {@code null} if none found or previously processed
*/
@Nullable
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
/*************************处理内部类配置类***********************************/
//判断该类是否包含@Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
//2.3.1递归处理内部类
processMemberClasses(configClass, sourceClass, filter);
}
/*************************处理@PropertySource注解*********************************/
// Process any @PropertySource annotations
//2.3.2处理@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
/*************************处理@ComponentScan***********************************/
// Process any @ComponentScan annotations
//2.3.3处理@ComponentScan注解
//这个方法和@PropertySource完全一样
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
//这个方法将扫描到的类转化为BeanDefinition,核心方法
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
//检查扫描到的类中有没有配置类,如果有,就调用parse方法进行解析(递归)
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
//只要类中有这5个注解(@Component,@ComponentScan,@ImportResource,@Import,@Bean)之一,就会执行下面方法
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
/*************************处理@Import***********************************/
// Process any @Import annotations
//2.3.4处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
/*************************处理@ImportResource***********************************/
//2.3.5处理@ImportResource注解
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
/*************************处理@Bean***********************************/
//2.3.6处理@Bean注解
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
/***********************处理接口的默认@Bean方法******************************/
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
/*************************返回当前配置类的父类*********************************/
// Process superclass, if any
//2.3.7如果有父类,返回当前配置类的父类
if (sourceClass.getMetadata().hasSuperClass()) {
//获取父类的完全限定名
String superclass = sourceClass.getMetadata().getSuperClassName();
//父类不能为jdk中的类
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
//缓存要处理的父类信息,避免重复处理
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
//返回父类完全限定名
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
2.3.1递归处理内部类
/**
* Register member (nested) classes that happen to be configuration classes themselves.
*/
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate<String> filter) throws IOException {
//使用ASM获取该配置类的内部类的SourceClass集合
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
//遍历所有的内部类
for (SourceClass memberClass : memberClasses) {
/**
* isConfigurationCandidate()该方法见2.1.3
* 就是判断该类是不是一个配置类
* 第二个判断条件就是两个类的名字不能一样
*/
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
//排序
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
/**
* 主要是为了避免循环嵌套问题
* 因为有的人可能会在内部类上使用@Import注解导入主类,见2.3.4.3
* 在处理内部类的时候,将主类记录到队列中,并且每次处理内部类是先去队列中判断
* 是否包含了该内部类的主类
*/
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
//主类压栈
this.importStack.push(configClass);
try {
/**
* 递归处理内部类
* 这里必须得说一下asConfigClass()方法
* 它构造了一个当前内部类的ConfigurationClass对象
*/
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
//内部类处理完成后,将该内部类对应的主类弹栈
this.importStack.pop();
}
}
}
}
}
asConfigClass()
方法非常重要,它为什么要传一个主类的ConfigurationClass
对象?废话不多说,直接看源码你就明白了
//又是两套流程,简单反射和ASM
public ConfigurationClass asConfigClass(ConfigurationClass importedBy) {
//this.source不就是当前内部类的clazz或MetadataReader
//简单反射
if (this.source instanceof Class) {
return new ConfigurationClass((Class<?>) this.source, importedBy);
}
//ASM
return new ConfigurationClass((MetadataReader) this.source, importedBy);
}
与之对应的
ConfigurationClass
的两个构造方法
//记录当前配置类是来源于那个配置类的,初始大小为1
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
/**
* Create a new {@link ConfigurationClass} representing a class that was imported
* using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}).
* @param clazz the underlying {@link Class} to represent
* @param importedBy the configuration class importing this one (or {@code null})
* @since 3.1.1
*/
public ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
//StandardAnnotationMetadata.from(clazz)
//简单反射获取AnnotationMetadata
this.metadata = AnnotationMetadata.introspect(clazz);
this.resource = new DescriptiveResource(clazz.getName());
//记录当前配置类是来源于那个配置类的
this.importedBy.add(importedBy);
}
/**
* Create a new {@link ConfigurationClass} representing a class that was imported
* using the {@link Import} annotation or automatically processed as a nested
* configuration class (if importedBy is not {@code null}).
* @param metadataReader reader used to parse the underlying {@link Class}
* @param importedBy the configuration class importing this one or {@code null}
* @since 3.1.1
*/
public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
//ASM
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
//记录当前配置类是来源于那个配置类的
this.importedBy.add(importedBy);
}
2.3.2处理@PropertySource
注解
//2.3.2.1获取到`@PropertySource`注解属性键值对
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
//2.3.2.2解析properties文件,并将内容加载到环境中
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
2.3.2.1获取到@PropertySource
注解属性键值对
首先我们先来看看这个
attributesForRepeatable
方法,它的返回值是Set<AnnotationAttributes>
,这个AnnotationAttributes
是个什么东西呢?看源码我们发现它继承了LinkedHashMap<String, Object>
,就是一个map集合,我们可以猜测,这个里面保存了注解属性的key-value
键值对。进入这个方法的源码
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
Class<?> containerClass, Class<?> annotationClass) {
//调用下面方法进行真正的处理
return attributesForRepeatable(metadata, containerClass.getName(), annotationClass.getName());
}
@SuppressWarnings("unchecked")
static Set<AnnotationAttributes> attributesForRepeatable(
AnnotationMetadata metadata, String containerClassName, String annotationClassName) {
Set<AnnotationAttributes> result = new LinkedHashSet<>();
// Direct annotation present?
/**
* @PropertySource注解
* getAnnotationAttributes() 获取对应注解所有属性键值对
*/
addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));
// Container annotation present?
/**
* @PropertySources注解
* 需要注意,这是两个注解,它们的属性键值对是不一样的
*
* getAnnotationAttributes(containerClassName, false)
* 也会解析value属性(@PropertySource注解),形成一个嵌套map
* 也就是说AnnotationAttributes中最终都是@PropertySource注解的属性键值对
*/
Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
if (container != null && container.containsKey("value")) {
for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
addAttributesIfNotNull(result, containedAttributes);
}
}
// Return merged result
return Collections.unmodifiableSet(result);
}
2.3.2.2解析properties
文件,并将内容加载到环境中
接下来我们看看processPropertySource(propertySource);
这个方法,进入源码
/**
* Process the given <code>@PropertySource</code> annotation metadata.
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
* @throws IOException if loading a property source failed
*/
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
//@PropertySource注解的name属性值
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
//@PropertySource注解的encoding属性值
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
//@PropertySource注解的value属性值
String[] locations = propertySource.getStringArray("value");
Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
//@PropertySource注解的ignoreResourceNotFound属性值
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
//创建一个PropertySourceFactory,它可以将properties文件的内容添加到环境中
//factory属性可以指定用户自定义的工厂
//默认工厂为DefaultPropertySourceFactory
Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
for (String location : locations) {
try {
//解析路径中的占位符
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
//获取对应文件的统一资源描述
Resource resource = this.resourceLoader.getResource(resolvedLocation);
//使用工厂将properties文件的内容添加到环境中
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
}
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
// Placeholders not resolvable or resource not found when trying to open it
if (ignoreResourceNotFound) {
if (logger.isInfoEnabled()) {
logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
总结:
(1)注解中可以写
SpEL
表达式(2)只能加载项目路径下的
properties
文件
2.3.3处理@ComponentScan
注解
//这个方法将扫描到的类转化为BeanDefinition,核心方法
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//componentScanParser是在ConfigurationClassParser构造方法初始化的,见2.2
//类型为ComponentScanAnnotationParser
我们看一下这个 parse
方法是如何扫描并解析类的
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
/**
* ClassPathBeanDefinitionScanner是一个很重要的类
* 能扫描到有@Repository,@Service,@Controller,@Component注解
* Java EE 6's @ManagedBean 和JSR-330's @Named的类,
* 将其转化为BeanDefinition
*
* 2.3.3.1ClassPathBeanDefinitionScanner构造方法
*/
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//判断在注解中是否指定扫描到的类的beanName生成器
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
//2.3.3.2判断扫描到的类是否使用代理
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
//设置扫描类路径是的资源模式,默认为"**/*.class",会添加到指定的包名后面
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
/**
* AnnotationAttributes中有一个getAnnotationArray()方法
* 它可以获取当前注解属性中包含的另一个注解信息数组
*
* scanner.addIncludeFilter(typeFilter)实际上就是添加过滤规则,
* 和ClassPathBeanDefinitionScanner构造方法中registerDefaultFilters()方法一样
* 只不过registerDefaultFilters()方法添加的是对@Component注解的过滤,
* 这个是我们定制的注解过滤
* 2.3.3.3添加自定义的过滤规则
*/
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
//2.3.3.4设置扫描到的类是否为懒加载
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
/**
* 从这里可以看到,basePackages还可以使用占位符(SpEL表达式),从环境中解析值
* ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS=",; \t\n"
*/
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
//获取指定类的包名
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
//未指定basePackages,就扫描当前注解所在类的包的所有类
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
//不扫描当前注解所在类
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//2.3.3.5开始扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
2.3.3.1ClassPathBeanDefinitionScanner
构造方法
这个构造方法里面其实也没做啥,就是初始化一些属性,但是我们需要看一下
registerDefaultFilters()
方法。
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
* using the given {@link Environment} when evaluating bean definition profile metadata.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata
* @param resourceLoader the {@link ResourceLoader} to use
* @since 4.3.6
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
//我们看一下这个方法
registerDefaultFilters();
}
setEnvironment(environment);
//这个方法也很重要,涉及到后面要说的组件索引
setResourceLoader(resourceLoader);
}
/**
* Register the default filter for {@link Component @Component}.
* <p>This will implicitly register all annotations that have the
* {@link Component @Component} meta-annotation including the
* {@link Repository @Repository}, {@link Service @Service}, and
* {@link Controller @Controller} stereotype annotations.
* <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
* JSR-330's {@link javax.inject.Named} annotations, if available.
* 添加过滤规则(@Component,@ManagedBean,@Named)
* 把有这三个注解的类过滤下来
*/
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
//@Component
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
//@ManagedBean
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
//@Named
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
/**
* Set the {@link ResourceLoader} to use for resource locations.
* This will typically be a {@link ResourcePatternResolver} implementation.
* <p>Default is a {@code PathMatchingResourcePatternResolver}, also capable of
* resource pattern resolving through the {@code ResourcePatternResolver} interface.
* @see org.springframework.core.io.support.ResourcePatternResolver
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
*/
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
//这里初始化的两个属性很重要,在后面都有用到
//resourcePatternResolver就是当前上下文
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
/**
* 在这里会去加载META-INF/spring.compononts文件
* 将文件内容封装到componentsIndex中,
* 以便后面直接根据索引找到对应类,加快扫描速度
*
* 如果不存在对应的文件,那个返回的对象就是空的
*/
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}
2.3.3.2判断扫描到的类是否需要使用代理
这个是非默认情况下
/**
* Specify the proxy behavior for non-singleton scoped beans.
* Note that this will override any custom "scopeMetadataResolver" setting.
* <p>The default is {@link ScopedProxyMode#NO}.
* @see #setScopeMetadataResolver
*/
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
//这里我们自己new
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode);
}
/**
* Construct a new {@code AnnotationScopeMetadataResolver} using the
* supplied default {@link ScopedProxyMode}.
* @param defaultProxyMode the default scoped-proxy mode
*/
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
Assert.notNull(defaultProxyMode, "'defaultProxyMode' must not be null");
this.defaultProxyMode = defaultProxyMode;
}
这个是默认情况下
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
//反射实例化resolverClass,使用的是默认构造方法
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
/**
* Construct a new {@code AnnotationScopeMetadataResolver}.
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
* @see ScopedProxyMode#NO
*/
public AnnotationScopeMetadataResolver() {
//默认情况下就是为No,不使用代理
this.defaultProxyMode = ScopedProxyMode.NO;
}
总结:这里我们可以看到,
@ComponentScan
设置的scopedProxy
属性值会被保存到AnnotationScopeMetadataResolver
的defaultProxyMode
属性中,后续处理见2.3.3.5(5-2)
2.3.3.3添加自定义的过滤规则
我们重点看一下这个
typeFiltersFor(filter)
方法
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
List<TypeFilter> typeFilters = new ArrayList<>();
//获取@ComponentScan中内部注解@Filter注解的属性
FilterType filterType = filterAttributes.getEnum("type");
for (Class<?> filterClass : filterAttributes.getClassArray("classes")) {
switch (filterType) {
//过滤注解,可过滤@Component注解就是用的这种方式,见构造方法
case ANNOTATION:
Assert.isAssignable(Annotation.class, filterClass,
"@ComponentScan ANNOTATION type filter requires an annotation type");
@SuppressWarnings("unchecked")
Class<Annotation> annotationType = (Class<Annotation>) filterClass;
//也就是说我们可以自定义注解,然后将该注解添加到过滤规则里面
typeFilters.add(new AnnotationTypeFilter(annotationType));
break;
//下面的几种我们目前用不到,等用到的时候在说
case ASSIGNABLE_TYPE:
typeFilters.add(new AssignableTypeFilter(filterClass));
break;
case CUSTOM:
Assert.isAssignable(TypeFilter.class, filterClass,
"@ComponentScan CUSTOM type filter requires a TypeFilter implementation");
TypeFilter filter = ParserStrategyUtils.instantiateClass(filterClass, TypeFilter.class,
this.environment, this.resourceLoader, this.registry);
typeFilters.add(filter);
break;
default:
throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
}
}
//下面这两种过滤规则也不常用
for (String expression : filterAttributes.getStringArray("pattern")) {
switch (filterType) {
case ASPECTJ:
typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader()));
break;
//这个应该是根据指定的完全限定类名过滤
case REGEX:
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
break;
default:
throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType);
}
}
return typeFilters;
}
2.3.3.4设置扫描到的类是否为懒加载
//获取@ComponentScan注解lazyInit属性值
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
/**
* 核心的代码这个这个
* 为什么在@ComponentScan注解中设置懒加载,然后它扫描到的组件默认就是懒加载的
* 功能就是在此处完成的
*/
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
在
ClassPathBeanDefinitionScanner
初始化的时候有private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
我们看一下
BeanDefinitionDefaults
这个类
public class BeanDefinitionDefaults {
@Nullable
//懒加载
private Boolean lazyInit;
private int autowireMode = AbstractBeanDefinition.AUTOWIRE_NO;
private int dependencyCheck = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE;
@Nullable
private String initMethodName;
@Nullable
private String destroyMethodName;
//还有一些对应的get,set方法,构造方法,都省略,这里主要看一下设置哪些默认属性
}
也就是说,
@ComponentScan
注解lazyInit
属性值设置到这个对象里面了。在后面会这个对象中的值设置到扫描出来的BeanDefinition
中,见2.3.3.5(5-4)
2.3.3.5开始扫描
经过前面设置的扫描参数后,现在开始扫描
/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* <p>This method does <i>not</i> register an annotation config processor
* but rather leaves this up to the caller.
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
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) {
//(5-1)核心方法,扫描包,创建对应类的BeanDefinition(ScannedGenericBeanDefinition)
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//进一步解析扫描的组件
for (BeanDefinition candidate : candidates) {
//(5-2)解析组件中的@Scope注解,获取ScopeMetadata
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//(5-3)使用BeanNameGenerate生成对应bean的名字
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//(5-4)向BeanDefinition设置一些默认属性
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//(5-5)处理bean中的一些其他注解
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//(5-6)判断当前BeanDefinition是否可以被注册到容器中(不是实例化)
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//(5-7)应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition)
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//注册到容器中,会注册BeanDefinition和别名
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
总结:这个方法可以说是
@ComponentScan
的核心方法,在这个方法里面完成对指定包的扫描,并且解析扫描到的组件中的@Scope
、@Lazy
、@Primary
、@DependsOn
、@Role
、@Description
注解。
(5-1)核心方法,扫描包,创建对应类的BeanDefinition
/**
* Scan the class path for candidate components.
* @param basePackage the package to check for annotated classes
* @return a corresponding Set of autodetected bean definitions
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//就是组件索引,方便找到组件(componentsIndex见2.3.3.1构造方法)
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
//根据索引快速扫描组件
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
//普通方式扫描
else {
return scanCandidateComponents(basePackage);
}
}
组件索引速扫描组件
这个是
spring
官方文档地址https://docs.spring.io/spring-framework/docs/5.1.12.RELEASE/spring-framework-reference/core.html#beans-scanning-index
要使用组件索引,必须引入下面依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.1.12.RELEASE</version>
<optional>true</optional>
</dependency>
有了这个依赖,spring就会在程序编译的时候,自动创建
META-INF/spring.components
文件,里面包含了对应类的索引。
文件内容大概如下
#
#Sun Dec 27 16:27:11 CST 2020
cn.lx.spring.v1.Config=org.springframework.stereotype.Component
cn.lx.spring.v1.Person=org.springframework.stereotype.Component
文件中直接记录了所有
@Component
注解标注类的限定名,这样做,可以在大型项目中显著提升启动性能。
/**
* Determine if the index can be used by this instance.
* @return {@code true} if the index is available and the configuration of this
* instance is supported by it, {@code false} otherwise
* @since 5.0
*/
private boolean indexSupportsIncludeFilters() {
//必须是所有过滤规则都通过才能使用组件索引
//我们默认的就一种过滤规则(@Component)
for (TypeFilter includeFilter : this.includeFilters) {
if (!indexSupportsIncludeFilter(includeFilter)) {
return false;
}
}
return true;
}
/**
* Determine if the specified include {@link TypeFilter} is supported by the index.
* @param filter the filter to check
* @return whether the index supports this include filter
* @since 5.0
* @see #extractStereotype(TypeFilter)
*/
private boolean indexSupportsIncludeFilter(TypeFilter filter) {
if (filter instanceof AnnotationTypeFilter) {
Class<? extends Annotation> annotation = ((AnnotationTypeFilter) filter).getAnnotationType();
/**
* isAnnotationDeclaredLocally()就是判断annotation注解中是否包含Indexed注解
* 经过我们查看@Component源码,我们发现,上面的确包含@Indexed注解
*/
return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) ||
annotation.getName().startsWith("javax."));
}
if (filter instanceof AssignableTypeFilter) {
Class<?> target = ((AssignableTypeFilter) filter).getTargetType();
return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target);
}
return false;
}
根据索引快速扫描组件
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
Set<String> types = new HashSet<>();
for (TypeFilter filter : this.includeFilters) {
//获取当前过滤规则的名字,实际上就是org.springframework.stereotype.Component
String stereotype = extractStereotype(filter);
if (stereotype == null) {
throw new IllegalArgumentException("Failed to extract stereotype from " + filter);
}
//根据@Component注解的完全限定名从索引中获取到有该注解的类的完全限定名
types.addAll(index.getCandidateTypes(basePackage, stereotype));
}
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (String type : types) {
//获取该类的MetadataReader
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
//再次判断类是否可以通过过滤规则(excludeFilters和includeFilters)
if (isCandidateComponent(metadataReader)) {
/**
* 通过MetadataReader初始化一个BeanDefinition
* 构造方法中就这三个方法
* this.metadata = metadataReader.getAnnotationMetadata();注解元数据
* setBeanClassName(this.metadata.getClassName());beanName
* setResource(metadataReader.getResource());统一资源描述
*/
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(metadataReader.getResource());
/**
* 这里又出现了isCandidateComponent()方法
* 这个方法是重载版的,我们需要弄清楚这两个方法的作用
*/
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Using candidate component class from index: " + type);
}
//添加到集合中,返回
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + type);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because matching an exclude filter: " + type);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
/**
* Determine whether the given class does not match any exclude filter
* and does match at least one include filter.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
*/
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
/**
* 先进行excludeFilters的过滤,我们已经知道里面只有一个过滤规则
* 那就是排除当前注解标注的类
*/
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
/**
* 先进行includeFilters的过滤,我们已经知道里面也只有一个过滤规则
* 那就包含@Component注解的类
*/
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
/**
* Determine whether the given bean definition qualifies as candidate.
* <p>The default implementation checks whether the class is not an interface
* and not dependent on an enclosing class.
* <p>Can be overridden in subclasses.
* @param beanDefinition the bean definition to check
* @return whether the bean definition qualifies as a candidate component
* 这个方法就是判断BeanDefinition是否符合条件了
*/
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
/**
* isIndependent() 判断当前BeanDefinition对应的类是否是独立类(顶级类,静态内部类)
* isConcrete() 是否非接口非抽象类
* hasAnnotatedMethods(Lookup.class.getName())是否有包含@Lookup注解的方法
*
* 成立条件:首先必须是独立类,其次要么是非抽象类非接口,要么是抽象类但是有@Lookup注解的方法
*/
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
普通方式扫描组件
很明显,这个是
ASM
的方式扫描组件,相比于反射的优点就是不需要将对应包下类加载到jvm
中,节省了jvm
的内存
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//包名加上前后缀
//ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX="classpath*:"
//classpath*:说明会去所有的jar包找
//this.resourcePattern="**/*.class"
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//获取当前的ResourcePatternResolver,实际上就是当前上下文对象
//获取到当前包下面所有类的资源
Resource[] resources = getResourcePatternResolver().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 = getMetadataReaderFactory().getMetadataReader(resource);
/**
* 两个同名方法isCandidateComponent()
* 并且BeanDefinition的类型都是ScannedGenericBeanDefinition
* 到了这一步,我们可以很明确的说扫描的类都是ScannedGenericBeanDefinition
*/
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
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;
}
(5-2)解析组件中的@Scope
注解,获取ScopeMetadata
ClassPathBeanDefinitionScanner
默认使用的ScopeMetadataResolver
就是AnnotationScopeMetadataResolver
,它是专门用来解析@Scope
注解的
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
解析@Scope
注解
//该方法实际上就是解析类上的@Scope注解,没有就使用默认值
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
//这个方法上面讲过,就是获取@Scope注解的全部属性键值对
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
//有@Scope注解,获取value属性和proxyMode属性
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
/**
* 这里面终于用到了this.defaultProxyMode这个属性
* 这个属性的来源就是@ComponentScan注解的scopedProxy属性,见2.3.3.2
*
* 你注意一下此时的成立条件
* 首先对应的类是不是得有@Scope注解
* 其次proxyMode属性必须为默认的ScopedProxyMode.DEFAULT
*
* 由上可以总结:@ComponentScan注解的scopedProxy属性是修改代理模式的默认值
* 并且需要使用@Scope注解才会生效
*/
proxyMode = this.defaultProxyMode;
}
//将代理模式设置到ScopeMetadata(作用域元数据)中
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
默认值
public class ScopeMetadata {
private String scopeName = BeanDefinition.SCOPE_SINGLETON;
private ScopedProxyMode scopedProxyMode = ScopedProxyMode.NO;
}
(5-3)使用BeanNameGenerate
生成对应bean的名字
生成的是短类名,见2.2指定的BeanNameGenerate
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
//获取@Component注解中指定的名字
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
//自动生成一个默认的名字
return buildDefaultBeanName(definition, registry);
}
/**
* Derive a bean name from one of the annotations on the class.
* @param annotatedDef the annotation-aware bean definition
* @return the bean name, or {@code null} if none is found
*/
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
//获取该bean的所有注解的完全限定名
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
//获取指定注解名的属性键值对
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null) {
Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
//获取key类上的注解的完全限定名,实际上就是注解上面的注解
//就比如@Component注解上面有@Indexed注解
Set<String> result = amd.getMetaAnnotationTypes(key);
return (result.isEmpty() ? Collections.emptySet() : result);
});
//检查是否允许获取注解中value属性值作为beanName
if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
}
return beanName;
}
/**
* Derive a default bean name from the given bean definition.
* <p>The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}.
* @param definition the bean definition to build a bean name for
* @param registry the registry that the given bean definition is being registered with
* @return the default bean name (never {@code null})
*/
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
//这个方法生成默认beanName
return buildDefaultBeanName(definition);
}
/**
* Derive a default bean name from the given bean definition.
* <p>The default implementation simply builds a decapitalized version
* of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
* <p>Note that inner classes will thus have names of the form
* "outerClassName.InnerClassName", which because of the period in the
* name may be an issue if you are autowiring by name.
* @param definition the bean definition to build a bean name for
* @return the default bean name (never {@code null})
*/
protected String buildDefaultBeanName(BeanDefinition definition) {
//这个方法获取bean的完全限定名
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
//工具类截取,得到短类名
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}
(5-4)向BeanDefinition
设置一些默认属性
这个需要我们的2.3.3.4
章节结合起来看
/**
* Apply further settings to the given bean definition,
* beyond the contents retrieved from scanning the component class.
* @param beanDefinition the scanned bean definition
* @param beanName the generated bean name for the given bean
*/
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
//private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
//将BeanDefinitionDefaults覆盖到BeanDefinition中
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
//这个没用到,不管
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
我们看一下这个applyDefaults
方法
/**
* Apply the provided default values to this bean.
* @param defaults the default settings to apply
* @since 2.5
* 将BeanDefinitionDefaults覆盖到BeanDefinition中
*/
public void applyDefaults(BeanDefinitionDefaults defaults) {
//调用set方法设值
Boolean lazyInit = defaults.getLazyInit();
if (lazyInit != null) {
setLazyInit(lazyInit);
}
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
(5-5)解析bean中的一些公共的注解
这个方法很简单,就是将这几个注解(@Lazy
、@Primary
、@DependsOn
、@Role
、@Description
)解析,然后将值设置到BeanDefinition
中
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
/**************************@Lazy************************************/
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"));
}
}
/**************************@Primary************************************/
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
/**************************@DependsOn************************************/
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
/**************************@Role************************************/
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
/**************************@Description************************************/
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
(5-6)判断当前BeanDefinition
是否可以被注册到容器中(不是实例化)
/**
* Check the given candidate's bean name, determining whether the corresponding
* bean definition needs to be registered or conflicts with an existing definition.
* @param beanName the suggested name for the bean
* @param beanDefinition the corresponding bean definition
* @return {@code true} if the bean can be registered as-is;
* {@code false} if it should be skipped because there is an
* existing, compatible bean definition for the specified name
* @throws ConflictingBeanDefinitionException if an existing, incompatible
* bean definition has been found for the specified name
*/
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
//不能存在同名BeanDefinition
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
//存在同名BeanDefinition,获取容器中的那个BeanDefinition
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
//判断是否兼容
//来自同一个Resource或者非扫描的,兼容
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
(5-7)应用@Scope
注解指定的代理模式(是否创建代理的BeanDefinition
)
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
//获取代理模式
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
//NO模式不做任何操作
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
//TARGET_CLASS模式则创建代理BeanDefinition
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
我们看一下创建代理的关键方法
/**
* Generate a scoped proxy for the supplied target bean, registering the target
* bean with an internal name and setting 'targetBeanName' on the scoped proxy.
* @param definition the original bean definition
* @param registry the bean definition registry
* @param proxyTargetClass whether to create a target class proxy
* @return the scoped proxy definition
* @see #getTargetBeanName(String)
* @see #getOriginalBeanName(String)
*/
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
//原始名
String originalBeanName = definition.getBeanName();
//目标BeanDefinition(被代理的BeanDefinition)
BeanDefinition targetDefinition = definition.getBeanDefinition();
//目标beanName(实际上就是在原始名字上加前缀"scopedTarget.")
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
/**
* 创建一个该clazz的BeanDefinition
* ScopedProxyFactoryBean是什么东西呢?翻看源码我们发现,它实现了FactoryBean
* 也就是说它可以使用getObject方法来生产bean
* 所以Scope创建代理对象就是通过这个getObject方法来做到的
*/
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
//将目标BeanDefinition设置到代理的BeanDefinition中
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
//目标bean的Resource
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
//目标beanName设置到代理BeanDefinition属性中
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
//true 表示用的是ScopedProxyMode.TARGET_CLASS模式,向BeanDefinition中设置对应值表示代理模式
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
//false 表示用的是ScopedProxyMode.INTERFACES模式
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
//拷贝目标beanDefinition属性到代理BeanDefinition
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
/**
* 将目标BeanDefinition注册到容器中,注册的名字上有前缀"scopedTarget."
* 在后面,还会将代理类也注册容器中,注册名字是原始名
*/
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
//此时proxyDefinition持有者的beanName是原始名
//那么以后代理BeanDefinition实例化,在容器中也是原始名
//这里有点AOP的感觉
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
2.3.4处理@Import
注解
//进入这个方法之前,我们得先看看getImports()方法干了啥
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
2.3.4.1SourceClass
类
这是
ConfigurationClassParser
的内部类,它的内部方法都非常重要。(1)它实现了
Ordered
接口,那么该类肯定可以进行排序,决定处理的先后顺序。(2)
Object source
注释上说了,它可以是一个clazz
对象也可以是MetadataReader·
对象,两种对象类型,很明显就对应了两种处理方式,一种是简单反射,一种是ASM
,看一下类的方法源码,确实如此。(3)
AnnotationMetadata metadata
这个没什么好说的,就是类的注解元数据
/**
* Simple wrapper that allows annotated source classes to be dealt with
* in a uniform manner, regardless of how they are loaded.
*/
private class SourceClass implements Ordered {
private final Object source; // Class or MetadataReader
private final AnnotationMetadata metadata;
/*****************************2.3.4.2中用到********************************/
/**
* 获取source类所有注解的SourceClass
* 注解和主类保持同样的加载方式
*/
public Set<SourceClass> getAnnotations() {
Set<SourceClass> result = new LinkedHashSet<>();
//当前类已经被加载到jvm中了,使用简单反射来获取所有注解信息
if (this.source instanceof Class) {
Class<?> sourceClass = (Class<?>) this.source;
for (Annotation ann : sourceClass.getDeclaredAnnotations()) {
Class<?> annType = ann.annotationType();
if (!annType.getName().startsWith("java")) {
try {
result.add(asSourceClass(annType, DEFAULT_EXCLUSION_FILTER));
}
catch (Throwable ex) {
// An annotation not present on the classpath is being ignored
// by the JVM's class loading -> ignore here as well.
}
}
}
}
//当前类未被加载到jvm,使用ASM获取类上所有注解信息
else {
//获取当前类的所有注解的完全限定名
for (String className : this.metadata.getAnnotationTypes()) {
//非java原生注解
if (!className.startsWith("java")) {
try {
/**
* 这里使用ASM解析className对应的文件,主要是为了解析注解上的注解
* 因为有的注解上面可能标注了@Import注解
*/
result.add(getRelated(className));
}
catch (Throwable ex) {
// An annotation not present on the classpath is being ignored
// by the JVM's class loading -> ignore here as well.
}
}
}
}
return result;
}
/**
* 根据完全限定名获取对应类的SourceClass
* 和主类保持同样的加载方式
*/
private SourceClass getRelated(String className) throws IOException {
//如果当前配置类已经被加载到jvm中了,就使用简单反射
if (this.source instanceof Class) {
try {
//获取className对应的clazz
Class<?> clazz = ClassUtils.forName(className, ((Class<?>) this.source).getClassLoader());
//简单反射获取类上注解的SourceClass
return asSourceClass(clazz, DEFAULT_EXCLUSION_FILTER);
}
catch (ClassNotFoundException ex) {
// Ignore -> fall back to ASM next, except for core java types.
if (className.startsWith("java")) {
throw new NestedIOException("Failed to load class [" + className + "]", ex);
}
return new SourceClass(metadataReaderFactory.getMetadataReader(className));
}
}
//使用ASM获取类上注解的SourceClass
return asSourceClass(className, DEFAULT_EXCLUSION_FILTER);
}
/**
* 获取当前配置类上指定注解指定属性的属性值对应的类的SourceClass
* 和主类保持同样的加载方式
* @param annType 注解的完全限定名
* @param attribute 注解的某一个属性名
*/
public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
//获取该注解所有属性键值对
Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
//校验这个SourceClass中是否包含该注解,是否包含该属性
if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
//空set集合
return Collections.emptySet();
}
//获取注解中attribute属性对应的值(导入的类的完全限定名)
String[] classNames = (String[]) annotationAttributes.get(attribute);
Set<SourceClass> result = new LinkedHashSet<>();
//遍历
for (String className : classNames) {
//使用和当前配置类同样的方式得到SourceClass
result.add(getRelated(className));
}
return result;
}
/*****************************2.3.4.3中用到********************************/
/**
* 判断指定类是否是当前类的超类或相同
* 根据当前类的加载方式使用不同的方式判断
* @param clazz 指定类
*/
public boolean isAssignable(Class<?> clazz) throws IOException {
if (this.source instanceof Class) {
//反射判断指定类是否是当前类的超类或相同
return clazz.isAssignableFrom((Class<?>) this.source);
}
//ASM反射判断指定类是否是当前类的超类或相同
return new AssignableTypeFilter(clazz).match((MetadataReader) this.source, metadataReaderFactory);
}
/**
* 获取当前类的clazz对象
* 当前类未加载到jvm中就先通过ASM获取完全限定名,然后forName加载到jvm中
*/
public Class<?> loadClass() throws ClassNotFoundException {
if (this.source instanceof Class) {
return (Class<?>) this.source;
}
String className = ((MetadataReader) this.source).getClassMetadata().getClassName();
return ClassUtils.forName(className, resourceLoader.getClassLoader());
}
/*****************************2.3.6.4中用到********************************/
//获取当前SourceClass的所有接口的SourceClass
public Set<SourceClass> getInterfaces() throws IOException {
Set<SourceClass> result = new LinkedHashSet<>();
//标准反射
if (this.source instanceof Class) {
Class<?> sourceClass = (Class<?>) this.source;
//反射获取所有父接口clazz
for (Class<?> ifcClass : sourceClass.getInterfaces()) {
result.add(asSourceClass(ifcClass, DEFAULT_EXCLUSION_FILTER));
}
}
//ASM
else {
//ASM获取所有父接口的完全限定名
for (String className : this.metadata.getInterfaceNames()) {
result.add(asSourceClass(className, DEFAULT_EXCLUSION_FILTER));
}
}
return result;
}
}
首先你得知道
DEFAULT_EXCLUSION_FILTER
是什么,它是一个匿名内部类,实现Predicate
接口,核心方法是test()
,
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
DEFAULT_EXCLUSION_FILTER
和asSourceClass()
是定义在这个内部类外部的主类ConfigurationClassParser
中的
//从这个test方法的实现,我们知道,它是判断className是不是一个java或者spring的原生注解
//spring的原生注解就是这几个@Component,@Repository,@Service,@Controller,@Indexed
private static final Predicate<String> DEFAULT_EXCLUSION_FILTER = className ->
(className.startsWith("java.lang.annotation.") || className.startsWith("org.springframework.stereotype."));
//当碰到java或spring原生注解时,直接返回这个SourceClass
private final SourceClass objectSourceClass = new SourceClass(Object.class);
接下来我们看一下这个asSourceClass()
,它有两个版本,分别对应简单反射和ASM
/**
* Factory method to obtain a {@link SourceClass} from a {@link Class}.
* 简单反射获取类上注解的SourceClass
*/
SourceClass asSourceClass(@Nullable Class<?> classType, Predicate<String> filter) throws IOException {
//这里调用了上面定义的DEFAULT_EXCLUSION_FILTER,过滤掉java和spring的原生注解
if (classType == null || filter.test(classType.getName())) {
//返回SourceClass(Object.class)
return this.objectSourceClass;
}
try {
// Sanity test that we can reflectively read annotations,
// including Class attributes; if not -> fall back to ASM
for (Annotation ann : classType.getDeclaredAnnotations()) {
AnnotationUtils.validateAnnotation(ann);
}
return new SourceClass(classType);
}
catch (Throwable ex) {
// Enforce ASM via class name resolution
return asSourceClass(classType.getName(), filter);
}
}
/**
* Factory method to obtain a {@link SourceClass} from a class name.
* ASM获取类上注解的SourceClass
*/
SourceClass asSourceClass(@Nullable String className, Predicate<String> filter) throws IOException {
//这里调用了上面定义的DEFAULT_EXCLUSION_FILTER,过滤掉java和spring的原生注解
if (className == null || filter.test(className)) {
//返回SourceClass(Object.class)
return this.objectSourceClass;
}
//jdk中的类使用反射获取类上注解的SourceClass
if (className.startsWith("java")) {
// Never use ASM for core java types
try {
return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load class [" + className + "]", ex);
}
}
//ASM获取类上注解的SourceClass
return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
}
2.3.4.2解析@Import
注解,获取需要导入的类的SourceClass
这个功能是由getImports()
方法完成的
/**
* Returns {@code @Import} class, considering all meta-annotations.
* 这个方法返回了一个SourceClass集合
*/
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
//@Import注解导入的类的SourceClass
Set<SourceClass> imports = new LinkedHashSet<>();
//递归已访问的SourceClass
Set<SourceClass> visited = new LinkedHashSet<>();
//解析sourceClass中@Import注解
collectImports(sourceClass, imports, visited);
return imports;
}
解析sourceClass
中@Import
注解
/**
* Recursively collect all declared {@code @Import} values. Unlike most
* meta-annotations it is valid to have several {@code @Import}s declared with
* different values; the usual process of returning values from the first
* meta-annotation on a class is not sufficient.
* <p>For example, it is common for a {@code @Configuration} class to declare direct
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
* annotation.
* @param sourceClass the class to search
* @param imports the imports collected so far
* @param visited used to track visited classes to prevent infinite recursion
* @throws IOException if there is any problem reading metadata from the named class
*/
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
/**
* 这是使用的深度优先算法
* 它可以访问到当前sourceClass所有的注解
* 但是方法里面设置3个过滤规则,非java非spring原生注解非@Import注解
* 对于其它的注解都会获取注解的SourceClass,然后调用getAnnotationAttributes
* 方法获取@Import注解信息
*/
if (visited.add(sourceClass)) {
/**
* getAnnotations()方法见2.3.4.1
* 就是获取到所有非java非spring原生注解的SourceClass
*/
for (SourceClass annotation : sourceClass.getAnnotations()) {
//当前注解的完全限定名
String annName = annotation.getMetadata().getClassName();
//当前注解不是@Import注解,就递归获取注解的注解
if (!annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
/**
* getAnnotationAttributes()方法见2.3.4.1
* 就是获取@Import注解导入的类的SourceClass
*/
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
2.3.4.3 导入@Import
注解指定的类(解析为BeanDefinition
,等待统一实例化)
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
//需要被导入的类集合为空直接返回
if (importCandidates.isEmpty()) {
return;
}
/**
* checkForCircularImports为true表示检查循环导入
* isChainedImportOnStack(configClass) 检查循环导入的方法
*/
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
//记录当前配置类,避免循环导入的问题
this.importStack.push(configClass);
try {
//遍历需要被导入的类
for (SourceClass candidate : importCandidates) {
/*********************ImportSelector********************/
//判断candidate是否是ImportSelector的子类,见2.3.4.1
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
//获得candidate的clazz对象,见2.3.4.1
Class<?> candidateClass = candidate.loadClass();
//(3-1)实例化ImportSelector
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
//(3-2)合并两个exclusionFilter的过滤器
exclusionFilter = exclusionFilter.or(selectorFilter);
}
//(3-4)DeferredImportSelector,延迟导入
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
//ImportSelector,不需要延迟导入
else {
//调用接口方法,获得所有需要导入类的完全限定名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//通过ASM获得指定完全限定名的SourceClass
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//递归调用处理@Import注解的方法
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
/******************ImportBeanDefinitionRegistrar*****************/
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
//(3-1)实例化ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
//(3-3)缓存ImportBeanDefinitionRegistrar到当前标注@Import注解配置类的ConfigurationClass上
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
/*********************普通的类*****************************/
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
/**
* 记录到importStack中
* ImportStack不仅本身继承对列,且里面包含了MultiValueMap<String, AnnotationMetadata> imports属性
* 此方法就是以被导入类的完全限定名为key,来源类的AnnotationMetadata为value保存到imports属性中
* 最终,在2章节中将importStack保存到环境中
*/
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//把被导入的类当成一个配置类进行处理,递归
//processConfigurationClass这个方法见2.3,它会处理被封装成ConfigurationClass的配置类
//asConfigClass()见2.3.1,会保存candidate配置类的来源类
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
//@Import注解处理完成,就去掉当前配置类
this.importStack.pop();
}
}
}
/**
* 检查循环导入
* 内部类上的@Import注解导入主类,报错
*/
private boolean isChainedImportOnStack(ConfigurationClass configClass) {
//importStack你就把它看成一个map集合的存,key为配置类的完全限定名,value为该配置类的AnnotationMetadata(注解元数据)
if (this.importStack.contains(configClass)) {
//获取当前处理的配置类的完全限定名
String configClassName = configClass.getMetadata().getClassName();
//根据名字获取缓存中的AnnotationMetadata
AnnotationMetadata importingClass = this.importStack.getImportingClassFor(configClassName);
//判断缓存中的AnnotationMetadata和当前处理的是否对应
while (importingClass != null) {
if (configClassName.equals(importingClass.getClassName())) {
return true;
}
importingClass = this.importStack.getImportingClassFor(importingClass.getClassName());
}
}
return false;
}
(3-1)实例化ImportSelector
或ImportBeanDefinitionRegistrar
/**
* Instantiate a class using an appropriate constructor and return the new
* instance as the specified assignable type. The returned instance will
* have {@link BeanClassLoaderAware}, {@link BeanFactoryAware},
* {@link EnvironmentAware}, and {@link ResourceLoaderAware} contracts
* invoked if they are implemented by the given object.
* @since 5.2
*/
@SuppressWarnings("unchecked")
static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo, Environment environment,
ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {
Assert.notNull(clazz, "Class must not be null");
Assert.isAssignable(assignableTo, clazz);
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
//获取类加载器
ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader());
/**
* 选用合适的构造方法实例化
* 什么叫合适的构造方法?
* 它会根据这个4个对象(environment,resourceLoader,registry,classLoader)去最大程度上匹配构造方法
*/
T instance = (T) createInstance(clazz, environment, resourceLoader, registry, classLoader);
//执行这4个Aware接口方法
ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader);
return instance;
}
(3-2)合并两个exclusionFilter
过滤器
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
* Predicate接口的核心方法
*/
boolean test(T t);
/**
* Returns a composed predicate that represents a short-circuiting logical
* OR of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
* 这是Predicate接口的有默认实现的方法
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
//函数式编程创建的一个匿名类
//实际上就是当前调用or方法的过滤器和参数传入的过滤器的test方法,只要成立一个,匿名类的test方法就返回true
return (t) -> { test(t) || other.test(t) };
}
(3-3)保存ImportBeanDefinitionRegistrar
到当前标注@Import
注解配置类的ConfigurationClass
上
//保存当前ImportBeanDefinitionRegistrar,等待后续处理
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
new LinkedHashMap<>();
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
(3-4)DeferredImportSelector
,延迟导入
deferredImportSelectorHandler
是ConfigurationClassParser
类的一个有默认值的属性
//延迟导入处理器
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
而DeferredImportSelectorHandler
是ConfigurationClassParser
的一个内部类
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
/**
* Handle the specified {@link DeferredImportSelector}. If deferred import
* selectors are being collected, this registers this instance to the list. If
* they are being processed, the {@link DeferredImportSelector} is also processed
* immediately according to its {@link DeferredImportSelector.Group}.
* @param configClass the source configuration class
* @param importSelector the selector to handle
*/
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
//构建一个延迟导入配置类的持有者
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
/**
* 2.3.8处理延迟导入会将this.deferredImportSelectors置空
* 说明此时已经在处理延迟导入了
* 就不需要保存到延迟导入处理器中,而是直接处理
* 具体的处理流程见2.3.8.2
*/
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
//保存到延迟导入处理器中,后续处理流程见2.3.8
this.deferredImportSelectors.add(holder);
}
}
总结@Import
注解的处理流程如下:
-
首先调用
getImports(sourceClass)
方法使用深度优先算法获取当前配置类所有@Import
注解(会去查找注解的注解)导入类的SourceClass
。 -
上面的方法处理完毕之后,会返回一个需要被导入的类的
SourceClass
集合,接下来就是调用processImports
方法处理这些需要被导入的类了。处理流程也很简单,根据这些类的类型分为三类处理- 如果是
ImportSelector
接口的实现类,那么就直接使用ParserStrategyUtils.instantiateClass()
方法实例化这个类,然后调用ImportSelector
接口的selectImports
方法获得这个导入器导入的类的完全限定名,得到完全限定名之后那就好办了,可以直接由asSourceClass
方法获得对应的SourceClass
,最后在递归接着调用processImports
方法处理这些需要被导入的类。 - 如果是
ImportBeanDefinitionRegistrar
接口的实现类,那么就直接使用ParserStrategyUtils.instantiateClass()
方法实例化这个类,然后将对象保存到标注@Import
注解配置类的ConfigurationClass
对象的importBeanDefinitionRegistrars
属性中,等待后续处理。 - 如果没有实现上面两个接口,就表明这个类是一个普通的配置类,那么就递归重新走一遍处理配置类的流程(
processConfigurationClass
方法,见2.3
)即可
- 如果是
2.3.5处理@ImportResource
注解
//获取ImportResource注解的所有属性信息
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
//获取xml文件的路径
String[] resources = importResource.getStringArray("locations");
//获取指定的BeanDefinitionReader
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
//解析路径上的占位符
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
//保存到ConfigurationClass中,等待后续处理
configClass.addImportedResource(resolvedResource, readerClass);
}
}
保存到ConfigurationClass
中,等待后续处理
//key为路径,value为BeanDefinitionReader,到时候会使用这个reader来读取解析路径所对应的文件
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<>();
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
this.importedResources.put(importedResource, readerClass);
}
2.3.6处理@Bean
注解
// Process individual @Bean methods
//获取所有@Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
//2.3.6.3保存到配置类的ConfigurationClass中等候统一处理
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
//2.3.6.4处理配置类接口有默认实现的@Bean方法
processInterfaces(configClass, sourceClass);
获取所有@Bean
方法
/**
* Retrieve the metadata for all <code>@Bean</code> methods.
*/
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
//获取当前配置类的注解元数据
AnnotationMetadata original = sourceClass.getMetadata();
//2.3.6.1获取配置类中有@Bean注解的方法元数据
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
//2.3.6.2对标准反射获取的方法元数据进行排序
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
// All reflection-detected methods found in ASM method set -> proceed
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return beanMethods;
}
2.3.6.1获取配置类中有@Bean
注解的方法元数据
@Override
public Set<MethodMetadata> getAnnotatedMethods(String annotationName) {
Set<MethodMetadata> annotatedMethods = null;
for (MethodMetadata annotatedMethod : this.annotatedMethods) {
//判断方法上的注解是不是annotationName
if (annotatedMethod.isAnnotated(annotationName)) {
if (annotatedMethods == null) {
annotatedMethods = new LinkedHashSet<>(4);
}
annotatedMethods.add(annotatedMethod);
}
}
return annotatedMethods != null ? annotatedMethods : Collections.emptySet();
}
方法很简单,但是我们需要看一下MethodMetadata
这个接口,它是spring
内部定义的描述方法的接口,spring
对接口提供两套实现,一种是使用反射来获取方法信息,另一种是ASM
来实现,具体的实现原理,这里不再深究,只需要知道这个接口有什么作用,能够做啥就行。
直接看类图
2.3.6.2对标准反射获取的MethodMetadata
(方法元数据)进行排序
jvm
标准反射会以任意的顺序返回MethodMetadata
,即使是在同一jvm
和同一应用程序中。
而ASM
则不相同,所以在这里会通过ASM
获取有@Bean
注解的方法,和反射获取的MethodMetadata
进行对比,以ASM
获取的为基准排序。
2.3.6.3保存到配置类的ConfigurationClass
中等候统一处理
//BeanMethod代表配置类中的一个@Bean标注方法的包装
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
将@Bean
标注的方法保存到ConfigurationClass
中beanMethods
属性中
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
public void addBeanMethod(BeanMethod method) {
this.beanMethods.add(method);
}
2.3.6.4处理配置类接口有默认实现的@Bean
方法
/**
* Register default methods on interfaces implemented by the configuration class.
*/
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//获取配置类所有接口的SourceClass,见2.3.4.1
for (SourceClass ifc : sourceClass.getInterfaces()) {
//获取ifc中有@Bean注解的方法元数据,见2.3.6.1
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
//非抽象方法就保存到配置类的ConfigurationClass对象中,见2.3.6.3
if (!methodMetadata.isAbstract()) {
// A default method or other concrete method on a Java 8+ interface...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
//递归处理接口的接口
processInterfaces(configClass, ifc);
}
}
2.3.7如果有父类,返回当前配置类的父类重复处理流程
//如果有父类
if (sourceClass.getMetadata().hasSuperClass()) {
//获取父类的完全限定名
String superclass = sourceClass.getMetadata().getSuperClassName();
//父类不能为jdk中的类
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
//记录下要处理的父类信息,避免重复处理
//一父类,两个子类的情况
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
//返回父类完全限定名
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
//没有父类,返回null,while条件判断直接终止
return null;
总结:
- 一个类只会被处理一次,无论它被多少个配置类继承。
- 不会处理
jdk
中的类。
2.3.8延迟处理@Import
注解导入的DeferredImportSelector
此处处理衔接2.3.4.3(3-4)
,也就是说这个接口的实现类,会在所有配置类解析完成后再进行处理。
2.3.8.1延迟导入所涉及的类
下面所有类均为ConfigurationClassParser
的内部类
延迟导入选择器持有者
private static class DeferredImportSelectorHolder {
//标注@Import注解的配置
private final ConfigurationClass configurationClass;
//延迟导入选择器对象
private final DeferredImportSelector importSelector;
public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
this.configurationClass = configClass;
this.importSelector = selector;
}
//省略两属性的get方法
}
延迟导入处理器
private class DeferredImportSelectorHandler {
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
/**
* Handle the specified {@link DeferredImportSelector}. If deferred import
* selectors are being collected, this registers this instance to the list. If
* they are being processed, the {@link DeferredImportSelector} is also processed
* immediately according to its {@link DeferredImportSelector.Group}.
* @param configClass the source configuration class
* @param importSelector the selector to handle
* 这个方法过程见2.3.4.3(3-4)
* 调用方法的时候,如果已经开始处理延迟导入,就直接处理,和process流程差不多
* 如果没有,就将它添加到等候处理的列表中
*/
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
//省略实现
}
/**
* 处理DeferredImportSelector
*/
public void process() {
//省略实现
}
}
延迟导入选择器组处理器
private class DeferredImportSelectorGroupingHandler {
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
//保存了延迟导入选择器来源的配置类的注解元数据和ConfigurationClass
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
//将延迟导入选择器持有者注册到指定的分组中
public void register(DeferredImportSelectorHolder deferredImport) {
//调用DeferredImportSelector接口getImportGroup()方法获取指定的分组
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
/**
* computeIfAbsent(k,Function) 如果map集合中存在k,就返回k对应的值,否则将接口方法的
* 返回值作为value保存到集合中,并返回value
*/
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
//保存来源类的注解元数据和ConfigurationClass
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
public void processGroupImports() {
//遍历组,按组导入
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
//获取当前分组合并后的exclusionFilter
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
//遍历所有需要被导入的Entry
grouping.getImports().forEach(entry -> {
//获取来源类的ConfigurationClass
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
//这个就是2.3.4.3的处理@Import注解指定类的方法
//也就是说延迟导入的类,又重新走一遍处理@Import注解的流程
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
//创建Group对象
private Group createGroup(@Nullable Class<? extends Group> type) {
//获取有效的Group
Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class);
//又是这个类的方法实例化Group对象,见2.3.4.3(3-1)
return ParserStrategyUtils.instantiateClass(effectiveType, Group.class,
ConfigurationClassParser.this.environment,
ConfigurationClassParser.this.resourceLoader,
ConfigurationClassParser.this.registry);
}
}
延迟导入选择器组
//表示当前分组有哪些延迟导入选择器持有者
//这个类主要就是为了包装Group
private static class DeferredImportSelectorGrouping {
//ConfigurationClassParser自带一个DefaultDeferredImportSelectorGroup内部类
//DefaultDeferredImportSelectorGroup自带的默认分组,用户可以自己实现该接口,创建新的分组
private final DeferredImportSelector.Group group;
//当前分组中包含的延迟导入选择器持有者
private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
DeferredImportSelectorGrouping(Group group) {
this.group = group;
}
//为当前分组添加DeferredImportSelectorHolder
public void add(DeferredImportSelectorHolder deferredImport) {
this.deferredImports.add(deferredImport);
}
/**
* Return the imports defined by the group.
* @return each import with its associated configuration class
* 获取当前分组的所有Entry
* Entry中只有两个属性
* AnnotationMetadata metadata 标注@Import注解配置类的注解元数据
* String importClassName 通过延迟导入选择器导入的某个类的完全限定名
*/
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//见下面默认分组的实现
//用户可以自定义实现对配置类的AnnotationMetadata做点什么
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
//process和selectImports是配套的
return this.group.selectImports();
}
/**
* 合并当前分组中所有延迟导入选择器的exclusionFilter
*/
public Predicate<String> getCandidateFilter() {
/**
* 默认的exclusionFilter
* 实际上就是排除java.lang.annotation开头和org.springframework.stereotype开头的类
*/
Predicate<String> mergedFilter = DEFAULT_EXCLUSION_FILTER;
//遍历当前分组中所有延迟导入选择器
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//获取延迟导入选择器的exclusionFilter(用户自定义的)
Predicate<String> selectorFilter = deferredImport.getImportSelector().getExclusionFilter();
if (selectorFilter != null) {
//合并,见2.3.4.3(3-2)
mergedFilter = mergedFilter.or(selectorFilter);
}
}
return mergedFilter;
}
}
默认的分组
private static class DefaultDeferredImportSelectorGroup implements Group {
private final List<Entry> imports = new ArrayList<>();
//构建一个Entry对象,然后缓存
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
for (String importClassName : selector.selectImports(metadata)) {
this.imports.add(new Entry(metadata, importClassName));
}
}
//返回缓存的Entry
@Override
public Iterable<Entry> selectImports() {
return this.imports;
}
}
2.3.8.2延迟导入处理流程
核心是DeferredImportSelectorHandler
类的process
方法
public void process() {
//取出缓存在ConfigurationClassParser的DeferredImportSelectorHolder
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
//这里置空,和handle方法对应了
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
//排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
//遍历调用register方法注册
deferredImports.forEach(handler::register);
//分组处理导入
handler.processGroupImports();
}
}
finally {
//方法返回前,创建一个空的集合
this.deferredImportSelectors = new ArrayList<>();
}
}
我们看一下是如何进行排序的
- 使用的是集合的排序方法,传入比较规则
private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR =
(o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector());
- 核心
compare
方法
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
//实现了PriorityOrdered接口的优先级最高
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
//两个中只有一个实现了PriorityOrdered接口
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
//获取PriorityOrdered接口或Ordered接口的或@Order注解的优先级值
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
延迟导入处理流程总结:
- 首先是扫描到配置类上的
@Import
注解,实例化之后发现注解导入的类是一个DeferredImportSelector
(延迟导入选择器)。- 将
DeferredImportSelector
对象保存到ConfigurationClassParser
的deferredImportSelectorHandler
属性对象中,等待所有配置类解析完成后处理。- 所有配置类解析完成,
ConfigurationClassParser
对象就会调用内部属性对象的deferredImportSelectorHandler.process()
方法,分组处理延迟导入。
2.4校验所有解析好的配置类
/**
* Validate each {@link ConfigurationClass} object.
* @see ConfigurationClass#validate
*/
public void validate() {
//校验每一个ConfigurationClass对象
for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
configClass.validate(this.problemReporter);
}
}
校验每一个ConfigurationClass
对象
public void validate(ProblemReporter problemReporter) {
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
//获取配置类中@Configuration注解属性键值对
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
//有@Configuration注解,且proxyBeanMethods属性值为true
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
//不能是final类
if (this.metadata.isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
//且需要校验该配置类中每一个BeanMethod对象
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
}
}
校验该配置类中每一个BeanMethod
对象,实际上就是@Bean
方法对象
@Override
public void validate(ProblemReporter problemReporter) {
//静态@Bean方法无需校验
if (getMetadata().isStatic()) {
// static @Bean methods have no constraints to validate -> return immediately
return;
}
/**
* 普通@Bean方法必须可以被重写,应为proxyBeanMethods属性值为true,需要创建代理
* 如何判断方法可以被重写,其实就是判断方法非final,非static,非private
*/
if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
if (!getMetadata().isOverridable()) {
// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
problemReporter.error(new NonOverridableMethodError());
}
}
}
校验总结:
- 只会校验有
@Configuration
注解,且proxyBeanMethods
属性值为true
的配置类。- 被校验的配置类不能是
final
,因为需要使用CGLIB
代理。- 还会校验配置类中所有的
@Bean
方法。@Bean
方法如果不是静态的,就必须可以被重写。
2.5使用ConfigurationClassBeanDefinitionReader
加载ConfigurationClass
中的BeanDefinition
/**
* Read {@code configurationModel}, registering bean definitions
* with the registry based on its contents.
*/
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
//加载每一个ConfigurationClass中的BeanDefinition
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
加载每一个ConfigurationClass
中的BeanDefinition
/**
* Read a particular {@link ConfigurationClass}, registering bean definitions
* for the class itself and all of its {@link Bean} methods.
*/
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//@Conditional注解处理
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
/**
* 2.5.1当前配置类是被别的配置类导入的(内部类或@Import注解)
* 这里很有意思,它只处理被别的配置类导入的ConfigurationClass,为什么不是所有的都处理呢
* 首先你得明白一点,如果当前配置类不是被别的配置类导入的,那么它的来源有哪几种呢?
* 第一种,XML文件中的bean标签定义,ClassPathXmlApplicationContext中的setConfigLocation方法指定XML文件位置
* 第二种,AnnotationConfigApplicationContext中的register方法指定配置类
* 只有这两种,并且spring在ConfigurationClassPostProcessor执行前已经生成BeanDefinition了
* 别的比如@ComponentScan扫描到的配置类和@Import注解导入的配置类均会记录其来源类
*/
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//2.5.2处理@Bean方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//2.5.3处理@ImportResource注解导入的资源
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//2.5.4处理@Import注解导入的ImportBeanDefinitionRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
2.5.1当前配置类是被别的配置类导入的(内部类或@Import
注解)
/**
* Register the {@link Configuration} class itself as a bean definition.
*/
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
//2.5.1.1根据置类的AnnotationMetadata创建一个BeanDefinition
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
//2.5.1.2解析配置类上的@Scope注解
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
//2.5.1.3生成当前配置类的BeanName
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
//2.5.1.4处理一些公共的注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
//2.5.1.5应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition)
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//2.5.1.6将beanName和BeanDefinition注册到容器中
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
//将生成当beanName保存到ConfigurationClass中
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
2.5.1.1根据配置类的AnnotationMetadata
创建一个BeanDefinition
在构造方法中解析出配置类的完全限定名,并保存
/**
* Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
* allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
* bean was discovered specifically via component-scanning as opposed to other means.
* @param metadata the annotation metadata for the bean class in question
* @since 3.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
//标准反射,获取当前类的完全限定名
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
//ASM,获取当前类的完全限定名
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
2.5.1.2解析配置类上的@Scope
注解
ConfigurationClassBeanDefinitionReader
默认使用的ScopeMetadataResolver
就是AnnotationScopeMetadataResolver
private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
它是专门用来解析@Scope
注解的,具体如何解析,在解析@ComponentScan
注解的时候已经说过了,见2.3.3.5(5-2)
2.5.1.3生成当前配置类的BeanName
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
首先这个importBeanNameGenerator
是通过ConfigurationClassBeanDefinitionReader
的构造函数赋值的,真正的对象是在ConfigurationClassPostProcessor
中定义的
/* Using fully qualified class names as default bean names by default. */
private BeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;
/**
* A {@code BeanNameGenerator} using fully qualified class names as default bean names.
* <p>This default for configuration-level import purposes may be overridden through
* {@link #setBeanNameGenerator}. Note that the default for component scanning purposes
* is a plain {@link AnnotationBeanNameGenerator#INSTANCE}, unless overridden through
* {@link #setBeanNameGenerator} with a unified user-level bean name generator.
* @since 5.2
* @see #setBeanNameGenerator
*/
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR =
new FullyQualifiedAnnotationBeanNameGenerator();
显然,此时生成的是完全限定名。
2.5.1.4处理一些公共的注解
这个方法很简单,就是将这几个注解(@Lazy
、@Primary
、@DependsOn
、@Role
、@Description
)解析,然后将值设置到BeanDefinition
中。
这个方法在解析@ComponentScan
注解的时候已经说过了,见2.3.3.5(5-5)
。
2.5.1.5应用@Scope
注解指定的代理模式(是否创建代理的BeanDefinition
)
这个方法在解析@ComponentScan
注解的时候已经说过了,见2.3.3.5(5-7)
。
2.5.1.6将beanName
和BeanDefinition
注册到容器中
要想理解这个方法,首先的明白BeanDefinition
的继承关系
总结:
- 所有的
BeanDefinition
都继承了AbstractBeanDefinition
- 加载
xml
中定义的bean
生成的是GenericBeanDefinition
@ComponentScan
注解扫描生成的是ScannedGenericBeanDefinition
@Import
注解导入和配置类的内部类生成的是AnnotatedGenericBeanDefinition
@Bean
方法生成的是ConfigurationClassBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
/**
* 方法重写和工厂方法不能同时存在
* 但是这个BeanFactoryPostProcessor没有获取@Lookup注解的功能
* 所以此时校验BeanDefinition相当于什么也没干
*/
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//容器中已存在该名字对应的BeanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//allowBeanDefinitionOverriding默认为true,表示允许BeanDefinition覆盖
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
//容器中的BeanDefinition角色优先级低于当前BeanDefinition,允许BeanDefinition覆盖
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
//两个BeanDefinition对象不相同,允许BeanDefinition覆盖
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//同时不满足上述三条件,也允许BeanDefinition覆盖
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//覆盖BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//容器中不存在该名字对应的BeanDefinition
else {
/**
* 判断容器中是否已经为BeanDefinition创建对象了
* 使用getBean方法创建对象的时候,会将已经创建成功的对象保存到工厂内部属性alreadyCreated中
* 此处方法就是直接检测alreadyCreated中元素个数是否为0
* 此时已经调用了getBean方法实例化ConfigurationClassPostProcessor
*/
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
//容器已经开始创建bean了,此时就得加锁,不能随意添加
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
//容器还未开始创建bean,此时可以直接添加
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
/**
* 如果当前beanName是工厂内部的Bean(environment,systemProperty,systemEnvironment)
* 就从列表中去掉该beanName
*/
removeManualSingletonName(beanName);
}
//将该属性置空,表明此时不冻结容器中的BeanDefinition(增删改操作)
this.frozenBeanDefinitionNames = null;
}
//containsSingleton方法判断容器单例对象池中是否包含beanName对应的对象
if (existingDefinition != null || containsSingleton(beanName)) {
//重置该beanName对应的BeanDefinition
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
//清空所有类型映射的缓存
clearByTypeCache();
}
}
重置该beanName对应的BeanDefinition
- 重置只会删除容器中的缓存,也就是除
beanDefinitionNames
和beanDefinitionMap
之外的一切相关的全部删除
/**
* Reset all bean definition caches for the given bean,
* including the caches of beans that are derived from it.
* <p>Called after an existing bean definition has been replaced or removed,
* triggering {@link #clearMergedBeanDefinition}, {@link #destroySingleton}
* and {@link MergedBeanDefinitionPostProcessor#resetBeanDefinition} on the
* given bean and on all bean definitions that have the given bean as parent.
* @param beanName the name of the bean to reset
* @see #registerBeanDefinition
* @see #removeBeanDefinition
*/
protected void resetBeanDefinition(String beanName) {
// Remove the merged bean definition for the given bean, if already created.
//删除容器中beanName对应的已经合并的BeanDefinition
clearMergedBeanDefinition(beanName);
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
//删除单例对象池中的对象,会删除一二三即缓存,并调用销毁方法(DisposableBean接口方法)
destroySingleton(beanName);
// Notify all post-processors that the specified bean definition has been reset.
//resetBeanDefinition方法通知该beanName对应的BeanDefinition已经重置
for (BeanPostProcessor processor : getBeanPostProcessors()) {
if (processor instanceof MergedBeanDefinitionPostProcessor) {
((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
}
}
// Reset all bean definitions that have the given bean as parent (recursively).
//递归,重置所有依赖该bean的BeanDefinition
for (String bdName : this.beanDefinitionNames) {
if (!beanName.equals(bdName)) {
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
// Ensure bd is non-null due to potential concurrent modification of beanDefinitionMap.
if (bd != null && beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}
2.5.2处理@Bean
方法
/**
* Read the given {@link BeanMethod}, registering bean definitions
* with the BeanDefinitionRegistry based on its contents.
*/
@SuppressWarnings("deprecation") // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
//获取@Bean方法所在配置类的ConfigurationClass
ConfigurationClass configClass = beanMethod.getConfigurationClass();
//获取@Bean方法的MethodeMetadata
MethodMetadata metadata = beanMethod.getMetadata();
//获取方法名
String methodName = metadata.getMethodName();
/**********************@Conditional注解处理********************/
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
//获取@Bean注解的全部属性键值对
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");
// Consider name and any aliases
//获取用户在@Bean注解上指定的名字
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
//第一个是beanName,其余的都是别名
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
//注册别名
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)?
/**
* 2.5.2.1判断容器中是否已经存在该beanName对应的BeanDefinition
*/
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
//@Bean注解注册的名字不能是配置类的名字
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
//跳过后面@Bean解析流程,不覆盖BeanDefinition了
return;
}
//2.5.2.2构造ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
/**
* this.sourceExtractor实际就是PassThroughSourceExtractor
* 它是SourceExtractor的一个简单实现(直接返回metadata)
* 这个接口的extractSource方法允许在获得源元数据之前对它进行修改
*/
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
//静态@Bean方法
if (metadata.isStatic()) {
// static @Bean method
//根据配置类AnnotationMetadata的获得类型,获取配置类的clazz或完全限定名
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
}
else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
//设置工厂方法名
beanDef.setUniqueFactoryMethodName(methodName);
}
//非静态@Bean方法
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
//配置类通过反射解析
if (metadata instanceof StandardMethodMetadata) {
//反射获取方法对象,并设置到BeanDefinition中
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
//设置自动注入的默认模式为构造方法自动注入
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
//兼容@Required注解,在spring5.1中已经废弃了该注解
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
/**
* 处理一些公共注解,见2.3.3.5(5-5)
* @Lazy、@Primary、@DependsOn、@Role、@Description
*/
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
//设置@Bean注解上指定的自动注入模式,在spring5.1中已经废弃了该属性
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
//该bean是否作为自动注入的候选bean
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
//设置@Bean注解上指定的初始化方法名
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
//设置@Bean注解上指定的销毁方法名
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// Consider scoping
//解析@Scope注解,并设置到BeanDefinition中,此处不是通过ScopeMetadataResolver解析
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
//应用@Scope注解指定的代理模式(是否创建代理的BeanDefinition),见2.3.3.5(5-7)
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, beanName);
}
if (logger.isTraceEnabled()) {
logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
//注册到容器中,见2.5.1.6
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
2.5.2.1判断容器中是否已经存在该beanName
对应的BeanDefinition
protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
//容器中不存在该beanName对应的BeanDefinition,直接返回false
if (!this.registry.containsBeanDefinition(beanName)) {
return false;
}
//存在,就获取该BeanDefinition
BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
// Is the existing bean definition one that was created from a configuration class?
// -> allow the current bean method to override, since both are at second-pass level.
// However, if the bean method is an overloaded case on the same configuration class,
// preserve the existing bean definition.
/**
* 如果这个BeanDefinition是@Bean方法创建的,且它们不是来源于同一配置类的@Bean方法,
* 返回false,否则true
* 因为它们都是第二级别
*/
if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
//比较它们来源的配置类是否相同
if (ccbd.getMetadata().getClassName().equals(
beanMethod.getConfigurationClass().getMetadata().getClassName())) {
//相同,再比较两个@Bean方法的方法名
if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
//覆盖原本的factoryMethodName,并将isFactoryMethodUnique置为false,表明该工厂方法需要被重写
ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
}
return true;
}
else {
return false;
}
}
// A bean definition resulting from a component scan can be silently overridden
// by an @Bean method, as of 4.2...
//如果是@ComponentScan注解扫描生成的BeanDefinition,直接返回false
if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
return false;
}
// Has the existing bean definition bean marked as a framework-generated bean?
// -> allow the current bean method to override it, since it is application-level
/**
* BeanDefinition.ROLE_APPLICATION=0 表明该BeanDefinition是应用程序级别的,一般用户定义的就是这个级别
* BeanDefinition.ROLE_SUPPORT=1 表明该BeanDefinition是某些较大配置的一部分
* BeanDefinition.ROLE_INFRASTRUCTURE=2 表明该BeanDefinition是框架内部定义的bean
* 非用户定义的直接false
*/
if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
return false;
}
// At this point, it's a top-level override (probably XML), just having been parsed
// before configuration class processing kicks in...
/**
* 到了这一步,就说明容器中的BeanDefinition可能是通过XML注册进来的,
* 那么就需要检查容器是否开启BeanDefinition覆盖的功能
*/
if (this.registry instanceof DefaultListableBeanFactory &&
!((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);
}
if (logger.isDebugEnabled()) {
logger.debug(String.format("Skipping bean definition for %s: a definition for bean '%s' " +
"already exists. This top-level bean definition is considered as an override.",
beanMethod, beanName));
}
return true;
}
总结:
这个方法返回
true
表明容器中存在的那个bean
是一个顶级bean
,此时不需要覆盖返回
false
,会继续解析@Bean
方法。false
存在以下几种情况
- 容器中不存在该
beanName
对应的BeanDefinition
- 这个
BeanDefinition
是@Bean
方法创建的,且它们不是来源于同一配置类的@Bean
方法@ComponentScan
注解扫描生成的BeanDefinition
- 存在的
BeanDefinition
不是BeanDefinition.ROLE_APPLICATION
(用户定义的)级别的
2.5.2.2构造ConfigurationClassBeanDefinition
public ConfigurationClassBeanDefinition(
ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {
//配置类的AnnotationMetadata
this.annotationMetadata = configClass.getMetadata();
//MethodMetadata
this.factoryMethodMetadata = beanMethodMetadata;
//就是beanName
this.derivedBeanName = derivedBeanName;
setResource(configClass.getResource());
//指定使用宽松模式解析构造方法(还有严格模式,未匹配上就抛异常)
setLenientConstructorResolution(false);
}
2.5.3处理@ImportResource
注解导入的资源
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
经由2.3.5
章节初步处理@ImportResource
注解后,这里做进一步处理。
//取出2.3.5章节保存在ConfigurationClass中的importedResources
public Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
return this.importedResources;
}
使用指定的BeanDefinitionReader
来读取资源。
private void loadBeanDefinitionsFromImportedResources(
Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
importedResources.forEach((resource, readerClass) -> {
// Default reader selection necessary?
//@ImportResource未指定reader属性
if (BeanDefinitionReader.class == readerClass) {
//根据资源的类型判断使用哪个默认的BeanDefinitionReader
if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
// When clearly asking for Groovy, that's what they'll get...
readerClass = GroovyBeanDefinitionReader.class;
}
else {
// Primarily ".xml" files but for any other extension as well
readerClass = XmlBeanDefinitionReader.class;
}
}
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
if (reader == null) {
try {
// Instantiate the specified BeanDefinitionReader
//实例化BeanDefinitionReader
reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
// Delegate the current ResourceLoader to it if possible
if (reader instanceof AbstractBeanDefinitionReader) {
AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
//设置一些必要的属性
abdr.setResourceLoader(this.resourceLoader);
abdr.setEnvironment(this.environment);
}
//缓存
readerInstanceCache.put(readerClass, reader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
}
}
// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
//读取资源
reader.loadBeanDefinitions(resource);
});
}
2.5.4处理@Import
注解导入的ImportBeanDefinitionRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
经由2.3.4.3(3-3)
章节初步处理@Import
注解后,这里做进一步处理。
//取出2.3.4.3(3-3)章节保存在ConfigurationClass中的importedResources
public Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> getImportBeanDefinitionRegistrars() {
return this.importBeanDefinitionRegistrars;
}
处理ImportBeanDefinitionRegistrar
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
/**
* 实际上就是遍历调用ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法
* metadata ImportBeanDefinitionRegistrar来源的配置类注解元数据
* registry BeanDefinitionRegistry注册BeanDefinition
* this.importBeanNameGenerator 当前使用的beanName生成器
*/
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
3postProcessBeanFactory
/**
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@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);
//此处判断该工厂是否经过2章节的处理
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//3.1代理容器中所有为full的配置类(CGLIB)
enhanceConfigurationClasses(beanFactory);
//3.2向容器中添加ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
3.1代理容器中所有为full
的配置类(CGLIB
)
/**
* Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
* any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
* Candidate status is determined by BeanDefinition attribute metadata.
* @see ConfigurationClassEnhancer
*/
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
//获取配置类标识(full或lite)
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
/**
* 对于ConfigurationClassBeanDefinition类型的BeanDefinition
* @Bean方法的MethodMetadata就是FactoryMethodMetadata
*/
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
//是一个配置类,就将该bean对应的class文件加载到JVM中
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
//ClassUtils.forName("完全限定名")加载到JVM
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
//full类型的配置类
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
//放入待代理集合中,等待代理
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
/************************代理full配置类*****************************/
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
//硬编码指定代理模式为CGLIB
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
//获取被代理类的clazz对象
Class<?> configClass = beanDef.getBeanClass();
//增强被代理类,获取代理类的clazz对象
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
//设置到BeanDefinition中,以后反射就使用代理的clazz实例化
beanDef.setBeanClass(enhancedClass);
}
}
}
3.2向容器中添加ImportAwareBeanPostProcessor
这个类了
InstantiationAwareBeanPostProcessorAdapter
,核心方法有两个
postProcessProperties()
属性赋值执行public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) { // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's // postProcessProperties method attempts to autowire other configuration beans. //就是将BeanFactory设置到代理的full配置类对象中 if (bean instanceof EnhancedConfiguration) { ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory); } return pvs; }
postProcessBeforeInitialization()
初始化前执行public Object postProcessBeforeInitialization(Object bean, String beanName) { /** * 只有通过@Import注解导入的非ImportBeanDefinitionRegistrar类型的组件才能实现这个接口ImportAware * 参考2.3.4.3章节,ImportStack保存了来源类的AnnotationMetadata * 也就是说被导入类可以通过实现ImportAware接口来获得来源类的AnnotationMetadata */ if (bean instanceof ImportAware) { //这不就是2中注册的ImportStack ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class); //根据名字获取对应的AnnotationMetadata AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName()); if (importingClass != null) { //调用接口方法设置到对象中 ((ImportAware) bean).setImportMetadata(importingClass); } } return bean; }
到此为止,该BeanFactoryPostProcesser
就已经分析完成了。