AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class)
一:这行代码为我们做了什么?
首先AnnotationConfigApplicationContext 继承了GenericApplicationContext,所以AnnotationConfigApplicationContext 初始化的时候会走一下GenericApplicationContext的构造函数。去创建一个叫做this.beanFactory =new DefaultListableBeanFactory();这样的默认Bean工厂。
父类的无参构造器
public GenericApplicationContext() {
//创建IOC容器
this.beanFactory = new DefaultListableBeanFactory();
}
这里为什么会new一个DefaultListableBeanFactory,因为,DefaultListableBeanFactory这个类是BeanFactory下实现功能最多的一个类。故此来构建它。
二、AnnotationConfigApplicationContext 构造方法都干了些什么?
首先看一下AnnotationConfigApplicationContext 的构造函数
/**
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//调用无参构造函数,会调用父类的无参构造器
this();
//注册配置类
register(componentClasses);
//容器刷新
refresh();
}
第一步:调用自己的无参构造
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
这里有两个东西,第一个是AnnotatedBeanDefinitionReader
。注解Bean定义的读取器,下图中的构造器有个getOrCreateEnvironment方法,是获取或者创建一个环境,并且加入缓存。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
回过头点开this,其中ConditionEvaluator 是@Condition注解的一个解析器。这个东西很重要。AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)很重要,重要的不能在重要,敲黑板,划重点。。。。。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
点进去看一下
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, (Object)null);
}
registerAnnotationConfigProcessors是注解的配置处理器,点进去看一下public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) {}如下图可知,这个类主要的作用是,将各种各样不同类型的类定义,注入到容器当中,注意,此时是Bean的定义并不是真正的创建Bean的实例到IOC容器中。就比如,洗浴中心要招一批小姐姐,规定身高180以上,体重120以下,只是定义。仅此而已。如下图可知,第一个Bean的定义ConfigurationClassPostProcessor.class。它是通过internalAutowiredAnnotationProcessor名字进行判断,注入的类型是ConfigurationClassPostProcessor。
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
RootBeanDefinition def;
if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
}
if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
}
if (jsr250Present && !registry.containsBeanDefinition("org.springframework.context.annotation.internalCommonAnnotationProcessor")) {
def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalCommonAnnotationProcessor"));
}
通过如下代码把BeanDefinition注册到容器中去:
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
还有如下下图所示,是解析Autowired自动配的
if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
}
总结:
registerAnnotationConfigProcessors(registry, (Object)null);的作用就是处理各种内部的组件。比如,AutoWired、Required、jsr250标准,JPA等等等。。。Bean定义它是用来描述Bean的,是否是懒加载等等等。
回过头在看看第二个东西AnnotationConfigApplicationContext(类路径下Bean扫描器)
,它的构造方法中的第二句话this.scanner =new ClassPathBeanDefinitionScanner(this);
这句话就比较牛逼了。
如下图所示,我们一直进入方法最后一层在类:ClassPathBeanDefinitionScanner下的ClassPathBeanDefinitionScanner方法中可以看到useDefaultFilters为true执行this.registerDefaultFilters();加载默认的配置策略。这也是之前的文章讲过的。在包扫描中如果使用includeFilters包含条件的话如果useDefaultFilters设为false就只会采用自定义的包扫描规则,如果为true是全量加载。
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
this.beanDefinitionDefaults = new BeanDefinitionDefaults();
this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
this.includeAnnotationConfig = true;
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
this.registerDefaultFilters();
}
this.setEnvironment(environment);
this.setResourceLoader(resourceLoader);
}
进入this.registerDefaultFilters()方法中
如下图所示,我的默认扫描规则是包含@Component注解的类。比如@Controller、比如@Service、比如@Confingration等等等等注解,如果不符合JSR-250、JSR-330标准就会抛出异常。
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
this.logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
} catch (ClassNotFoundException var4) {
;
}
try {
this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
this.logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
} catch (ClassNotFoundException var3) {
;
}
}
至此如下图的两端代码分析结束,第一个的主要作用是,注册内部的组件(比如:注解配置的处理器)Bean定义到容器中。第二个是扫描策略。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
第二步:第二个方法this.register(annotatedClasses);
/**
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//调用无参构造函数,会调用父类的无参构造器
this();
//注册配置类
register(componentClasses);
//容器刷新
refresh();
}
抛出结论:这段代码就是将我们自己传入进来的MainConfig类注册到容器中去。如以下代码所示,进入方法最后找到类AnnotatedBeanDefinitionReader中的registerBean方法。前面大概的意思就是说看我们的类上有没有@Primary、@Lazy、这些个东西。最后通过BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);这个方法,将我们的自己配置的类(跟容器内部的类区别开
)注册到容器中。
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
int var10;
int var11;
if (qualifiers != null) {
Class[] var9 = qualifiers;
var10 = qualifiers.length;
for(var11 = 0; var11 < var10; ++var11) {
Class<? extends Annotation> qualifier = var9[var11];
if (Primary.class == qualifier) {
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
} else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
BeanDefinitionCustomizer[] var13 = customizers;
var10 = customizers.length;
for(var11 = 0; var11 < var10; ++var11) {
BeanDefinitionCustomizer customizer = var13[var11];
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
以上this()、register(componentClasses)这两个方法分析完毕。
三:this.refresh()
最重要,也是最难理解的一个方法。无论是Spring还是SpringBoot都是通过这个方法去带动的。故此非常非常之重要。并且这里面的功能多的吓死人。下面逐一分析。
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
1,上面说过ConfigurationClassPostProcessor这个类非常的重要,一定要记住它。点进来看一下,如下图所示。他是BeanDefinitionRegistryPostProcessor类型,我们先记住这个接口
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR = new FullyQualifiedAnnotationBeanNameGenerator();
private static final String IMPORT_REGISTRY_BEAN_NAME = ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
private final Log logger = LogFactory.getLog(this.getClass());
private SourceExtractor sourceExtractor = new PassThroughSourceExtractor();
private ProblemReporter problemReporter = new FailFastProblemReporter();
@Nullable
private Environment environment;
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@Nullable
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
private boolean setMetadataReaderFactoryCalled = false;
private final Set<Integer> registriesPostProcessed = new HashSet();
private final Set<Integer> factoriesPostProcessed = new HashSet();
@Nullable
private ConfigurationClassBeanDefinitionReader reader;
private boolean localBeanNameGeneratorSet = false;
private BeanNameGenerator componentScanBeanNameGenerator;
private BeanNameGenerator importBeanNameGenerator;
}
2,回到refresh()方法中来,看一下如下图所示,调用了一个Bean工厂的后置处理器invokeBeanFactoryPostProcessors(beanFactory);
3,点进这个方法可以看一下,如下图所示,看第一个if判断的是beanFactory是不是Bean的注册器。其实这个 beanFactory就是我们一开始构建的那个DefaultListableBeanFactory类。那么点进这个类,会发现它属于bean的注册器。
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet();
ArrayList regularPostProcessors;
ArrayList registryProcessors;
int var9;
ArrayList currentRegistryProcessors;
String[] postProcessorNames;
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
regularPostProcessors = new ArrayList();
registryProcessors = new ArrayList();
Iterator var6 = beanFactoryPostProcessors.iterator();
while(var6.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
4,既然是Bean的注册器,那么就会进入第一个if判断,然后将beanFactory转成Bean的注册器,下面有两个list。第一个list可以解释为普通的PostProcessors,就是非BeanDefinitionRegistryPostProcessor类型的list。此时看while循环,这个循环根本就不会进来,因为传入的beanFactoryPostProcessors是一个半成品,并未有值。是一个空对象而已。while循环里只是做了,对两种类型的分类。并且放到regularPostProcessors和registryProcessors里面去。
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
regularPostProcessors = new ArrayList();
registryProcessors = new ArrayList();
Iterator var6 = beanFactoryPostProcessors.iterator();
while(var6.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}
5,再往下看代码,如图所示,红框1内表示创建一个(当前正在注册的一个处理器)。再往下看,红框2,实际上postProcessorNames数组就是我们之前在this()中加载的Bean的注册器BeanDefinitionRegistryPostProcessor
。红框三中的currentRegistryProcessors.add表示往容器中第一次调用,放入了一个Bean并且放入单例缓存池中具体细节其他章节阐述。processedBeans.add(ppName);这句话代表的是将Bean的注册器放入方法第一行定义的Set中。其次后面的代码不重要,重要的是invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);这句话
6,如果没invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);这句话,我们自定义的Bean根本就不会被注册进来。点击进入方法内。可以看到postProcessors他的类型就是前面讲的最重要的那个类型ConfigurationClassPostProcessor
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
Iterator var2 = postProcessors.iterator();
while(var2.hasNext()) {
BeanDefinitionRegistryPostProcessor postProcessor = (BeanDefinitionRegistryPostProcessor)var2.next();
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
7,同样点进去看看方法内,找到ConfigurationClassPostProcessor类中postProcessBeanDefinitionRegistry方法看看如何做的。我们主要看最后一行,处理配置Bean定义信息。直接点进去
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
} else if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
} else {
this.registriesPostProcessed.add(registryId);
this.processConfigBeanDefinitions(registry);
}
}
9,看下图中第二个红框内的代码,其他的看不懂不要紧,但至少能看懂两个东西,第一个是包扫描的生成器,起一个名字。第二个通过import注解导入的也要起个名字。
//@Order注解的排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry)registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
10,接着往下看,如下图所示通过注释可知,这段代码是对Bean的配置类的解析,创建一个Bean的解析器。这里使用了一个do-while循环,其中candidates集合表示候选的,alreadyParsed集合表示已解析的,但是长度设为了1.其作用就是使用了do-while循环,肯定先执行一次。节省内存。那么最核心的解析代码是parser.parse(candidates);点进去看一下。
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
HashSet alreadyParsed = new HashSet(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
}
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();
Iterator var12 = alreadyParsed.iterator();
while(var12.hasNext()) {
ConfigurationClass configurationClass = (ConfigurationClass)var12.next();
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
String[] var23 = newCandidateNames;
int var24 = newCandidateNames.length;
for(int var14 = 0; var14 < var24; ++var14) {
String candidateName = var23[var14];
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());
11,点进parse方法,我们的MainClass是通过注解的形式定义的。所以走AnnotatedBeanDefinition条件的parse方法。点进去。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
Iterator var2 = configCandidates.iterator();
while(var2.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
} else {
this.parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException var6) {
throw var6;
} catch (Throwable var7) {
throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
}
}
this.deferredImportSelectorHandler.process();
}
12,解析配置类
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
this.processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
13,点进去以后,其他的都不用看直接看下面,doProcessConfigurationClass这个代码。为什么?因为Spring真正干活的类,基本都是以do开头的方法名(小技巧)点进去
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter);
do {
sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
} while(sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
}
14,点进去我们发现AnnotationConfigUtils.attributesForRepeatable这个方法,他是用来进行解析我们的Component注解的。将这个注解解析成一个对象如下图所示。
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass, Predicate<String> filter) throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
this.processMemberClasses(configClass, sourceClass, filter);
}
Iterator var4 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();
AnnotationAttributes importResource;
while(var4.hasNext()) {
importResource = (AnnotationAttributes)var4.next();
if (this.environment instanceof ConfigurableEnvironment) {
this.processPropertySource(importResource);
} else {
this.logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
}
}
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
Iterator var14 = componentScans.iterator();
while(var14.hasNext()) {
AnnotationAttributes componentScan = (AnnotationAttributes)var14.next();
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
Iterator var8 = scannedBeanDefinitions.iterator();
while(var8.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var8.next();
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
this.parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
this.processImports(configClass, sourceClass, this.getImports(sourceClass), filter, true);
importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
String[] var20 = resources;
int var22 = resources.length;
for(int var23 = 0; var23 < var22; ++var23) {
String resource = var20[var23];
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
Set<MethodMetadata> beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
Iterator var18 = beanMethods.iterator();
while(var18.hasNext()) {
MethodMetadata methodMetadata = (MethodMetadata)var18.next();
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
this.processInterfaces(configClass, sourceClass);
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
return sourceClass.getSuperClass();
}
}
return null;
}
15,下面这段代码才是真正的对你的包扫描进行解析。上面那点,就好比,你发现了她是一个小姐姐,下面红框下的代码才是真正的对这个小姐姐进行分析,底盘扎实不扎实,发动机是否好用,变速箱是否换挡顺畅等等等一系列的信息。然后我们直接点进parse方法看一下
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
Iterator var14 = componentScans.iterator();
while(var14.hasNext()) {
AnnotationAttributes componentScan = (AnnotationAttributes)var14.next();
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
Iterator var8 = scannedBeanDefinitions.iterator();
while(var8.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var8.next();
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
this.parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
16,进入parse方法以后可以看到创建了一个扫描器。ClassPathBeanDefinitionScanner scanner =new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);然后,把上面解析的Component的值搂出来,逐一的给扫描器赋值进行初始化,真正干活的方法是最后的的这句:return scanner.doScan(StringUtils.toStringArray(basePackages));
17,通过下面的代码可知找到候选的一个组件。并且给我们拼接路径,找到这个包下所有子包的类,并且转换成Resource,并且里面存储的就是我们自己想要的组件。然后循环resource,判断是不是可读的,然后转换成一个原信息的读取器。到这里仅仅是将我们的Bean定义扫描到容器中去,并不是Bean的实例化。接着判断是否有包含或者排除的组件。接下来往下执行,如果遇到@Controller的组件,就会进行赋值。因为@Controller是可读的。此方法执行完毕以后回到doScan方法。进行循环
18,此时可以看到容器中并没有我们自己的组件,但是解析包扫描是找到的。然后接着往下看。原来是6个。现在还是6个
19,执行完registerBeanDefinition(definitionHolder, this.registry);注册Bean扫描器以后我们自己定义的组件就被扫描出来了。doScan执行完以后回到this.componentScanParser.parse这个地方。
20,在this.componentScanParser.parse的最下面又执行了一次parse,它作用是扫描比如在@Controller注解上有没有其他ComponentScan注解。正常的逻辑是不会有的。所以这个功能有点儿多余,不清楚为什么要这么设计。
21,代码继续往下走,执行这句话processImports。解析完可读的注解以后,在继续扫描类上面有没有import注解,如果有,就进去,并且找到import注解的value值。并且判断是否是导入的ImportSelector或者是ImportBeanDefinitionRegistrar。或者是DeferredImportSelector这种类型(这个东西很重要,自动注入,SpringBoot进行自动注入就是通过这个东西进行处理的)进行保存。保存之后就会有调用
22,processImports执行完以后往下看找到// Process individual @Bean methods,点击去之后发现,这个段代码的意思是,是解析@Bean标注的方法。最后执行完,回到parse方法。
23,这是我们新扫描出来的两个Bean的定义接着往下看
24,这个方法很重要。如果说在你的@Bean注解标注的方法内创建了一个类的实例,在未执行此方法的时候,那么那个实例是不会被加入到Bean定义注册器的,只有执行了这个方法以后才会在Bean的注册器中被注册。可以推断,这个方法就是用来将@Bean标注的方法内实例化的对象搂出来,放入Bean自定义的注册器中。并且如果是Import导入的类,也会将该类加入Bean的自定注册器中去,点开源码看。
25,this.reader.loadBeanDefinitions(configClasses);点开源码发现。通过import注解导入的类会通过红框内的方法进行注册,点进去看一下
26,进入这个方法以后,这个方法获取了你的方法名,这也是为什么Bean的依赖注入如果不指定别名,就是默认的方法名的原因。还进行了一系列的判断,接着往下看。
27,在方法的最后调用了this.registry.registerBeanDefinition(beanName, beanDefToRegister);方法。这段代码最关键。执行完以后会发现,@Bean注解标注的方法内,如果通过new关键字实例化的对象,此时已经被加入Bean定义注册器当中了。是不是很神奇?
28,回过头总结一下
- parser.parse(candidates);这句话仅仅是注册包扫描的。
- this.reader.loadBeanDefinitions(configClasses);这段代码是加载通过@import、@ Bean倒进来的。同理,SpringBoot也是通过这个东东来扫描各大装配种类的。
后面的代码是判断有没有解析完。看看有没有,没有解析的类。一笔带过了。如果都解析过,do-while循环就结束了。至此下图所示的一个方法就分析完毕了。