Springboot就不用多了吧,解放Java开发双手的神器。
最显著的特点就是,去配置化,自动装配,自动配置。让开发人员只需要注重业务的开发
今天就来了解一下自动装配的源码是怎么实现的
预先准备
- 直接引用springboot包2.5.6的
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
</parent>
- 再贴一下以前的MVC扫描包的web.xml配置
<!-- 一般applicationContext里面会有扫描包路径配置 -->
<context:component-scan base-package="com.demo.xxx"></context:component-scan>
以前是有入口指定扫描路径,但是springboot又没有这个配置,确也能扫描出来是怎么实现的,来一探究竟吧!
流程概括
- 入口肯定是run方法,参数传入的是当前的启动类
- 在容器初始化之前传入的启动类注册到容器中去,然后再刷新容器refresh()
- 在容器注册阶段完成后,就是将所有的需要加载类注册到BeanDefinitionMap了
- 然后在上下文中调用注册bean的处理器回调,在springboot包中解析bean
- 关注点在注册类,解析该类时得到扫描路径即当前路径 ‘.’ ,也就说明了springboot项目默认扫描到启动类那一层,扫描我们手写的代码后注册到容器,但是所需依赖还是没有想容器注册的
- 启动类上有@Import注解,解析时会一并处理,然后获取import的类的回调来获取需要自动装配的类
- 在回调类中解析需要自动装载的类,通过读取包内文件目录下META-INF/spring.factories的配置中获取对应key的值
- 最终想容器注册,自动装配流程到此完结
源码分析
上面流程中可以分为三步,一步一步分析。
1.向容器注册启动类
- 入口就是run()方法,直接到源码中去
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args){
//primarySource 启动类
return run(new Class<?>[] { primarySource }, args);
}
- 接下来run一直往下到
SpringApplication#run()
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
//获取需要注册的监听
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//环境和配置 后面会讲到
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
//打印启动banner
Banner printedBanner = printBanner(environment);
//创建web容器
context = createApplicationContext();
//设置web容器的启动类 DefaultApplicationStartup
context.setApplicationStartup(this.applicationStartup);
//为容器初始化之前做一些准备 ### 我们主要先看这里
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//初始容器
refreshContext(context);
//初始化完成
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//容器创建完成的通知
listeners.started(context);
//回调callRuners 即实现了CommandLineRunner接口的回调
callRunners(context, applicationArguments);
}catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
//容器已启动的通知
listeners.running(context);
}catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
- 先看容器加载前的处理
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//容器的一些设置
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//向容器注册一些单列bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
//这块是重点 getAllSources()里返回的是run方法里面传入的xxx.class,其实就是启动类
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//从上面得知这里传入的sources其实就是启动类 接下来看这里是怎么加载的 ###
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
- 这里拿到的是启动类,那么load的就是class,一直往下到
BeanDefinitionLoader#load(Class<?> source)
private void load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
}
//return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
//不是空的类 不是Groovy闭包 也不是匿名类 就直接向容器注册
if (isEligible(source)) {
//也就是说先将
this.annotatedReader.register(source);
}
}
//this.annotatedReader.register(source)接下来 会注册到IOC容器中去
AnnotatedBeanDefinitionReader
-> registerBean(componentClass)
-> doRegisterBean
-> BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
到这里第一个点就完成,本意就是把启动类注册到容器中去,然后在上下文中回调中用大到该类完成扫描业务代码,因为没有地方配置让spring扫描哪些包名下的类,类似完成web.xml中的component-scan配置
2.向容器注册业务类
- 接下来回到最开始的
SpringApplication#run
,找到以下代码
//容器刷新前
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//重点看这个 刷新容器 ###
refreshContext(context);
//一直往下 接下来到这里
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
//接下来又到 AbstractApplicationContext.refresh() IOC名场面了
//多的就不说了 直接看这个
// Invoke factory processors registered as beans in the context.
// 在上下文中调用注册为bean的工厂处理器 就是回调
invokeBeanFactoryPostProcessors(beanFactory);
//往下到这里
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
- 接下来到
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
,只贴关键代码
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
//省略部分代码
......
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//调用实现类
//这里还要注意一下 断点调试spring包实现了这个类的只有一个
//就是ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//添加到列表
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//针对于注册的bean进行回调 接下来看这里 ###
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
//省略部分代码
......
}
//invokeBeanDefinitionRegistryPostProcessors
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
//开始对实现了BeanDefinitionRegistryPostProcessor接口的bean进行回调
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}
- 经过断点调试,会到spring-context-5.3.12.jar包下的
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
- 需要注意的一个点,前面已经说到手动注册了启动类,那么candidateNames里面肯定会有启动类。其他的类我们忽略,主要看启动类的扫描和加载
//一直往下到这里
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//判断是否加了 @Configuration 这个注解
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//满足就加到list中 这里的启动类肯定是加了这个注解的 可以自己进行验证
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//省略部分代码
......
// Parse each @Configuration class
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 {
//开始解析带有@Configuration注解的类 ###先看这个
parser.parse(candidates);
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());
}
//把需要加载的类注册到容器中去
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//省略部分代码
......
}
- 先看下
parser.parse(candidates);
做了什么,到ConfigurationClassParser#parse()
ublic void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//启动类注解了@Configuration 属于注解annotation definition
if (bd instanceof AnnotatedBeanDefinition) {
//接下来走这里 ##
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
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);
}
}
//分析完parse后 在来分析这个process
this.deferredImportSelectorHandler.process();
}
- 一直往下到真正干活的类,
ConfigurationClassParser#doProcessConfigurationClass
解析核心类
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
processMemberClasses(configClass, sourceClass, filter);
}
//@PropertySource注解
// Process any @PropertySource annotations
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注解 扫描对应的包路径
//@SpringBootApplication上面有该注解,也可以自己指定
// Process any @ComponentScan annotations
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
//查找ComponentScan注解是否有使用value
//接下来先看看怎么扫描的 ####
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
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//@Import注解 先分析完扫描 下一步再重点看这里 ###
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//@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 注解的方法
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
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;
}
@ComponentScan
指定扫描包路径,ConfigurationClassParser#doProcessConfigurationClass
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
-> ComponentScanAnnotationParser.parse
//到这个方法
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//省略部分代码
......
Set<String> basePackages = new LinkedHashSet<>();
//获取手动写的扫描包路径 就是注解里面写的包路径
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
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()) {
//接下来看这里
//public static String getPackageName(String fqClassName) {
//Assert.notNull(fqClassName, "Class name must not be null");
//int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
//return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
//}
// 然后发现了 private static final char PACKAGE_SEPARATOR = '.';
//那么拿到的就是启动类的包名路径,这也验证了springboot 项目默认扫描到启动类那一层
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//扫描指定包路径下的类文件 接下来我看继续往下看 ###
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
- 接下来到
ClassPathBeanDefinitionScanner#doScan()
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//往下看 找到这里 ###
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//回调 因为此时容器已经处理回调这一步 所以新注册的bean需要自己回调
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//向容器注册 这里就不多说了
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
- 接下来到
ClassPathScanningCandidateComponentProvider#findCandidateComponents
->scanCandidateComponents
//这不就是混熟悉的读流了
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//resourcePattern = **/*.class class后缀
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//读流
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//满足注解的 @Component 其实所有需要加载的注解 都实现了@Component
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
//把对应路径下的class文件扫描到list中 然后向容器中注册
candidates.add(sbd);
}
.... //省略部分代码
return candidates;
}
到这里为止,已经把我们自己写的业务代码注册到容器中了,但是springboot框架需要依赖的bean还是没有注册的,接下来看下自动装配怎么实现的吧
3.向容器注册所需依赖的自动装配的类
- 我们回到
ConfigurationClassParser.doProcessConfigurationClass
方法中
//找到这行对 @import注解的解析
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//接下来到processImports这个方法里面 找到这一部分 只有加了@Import注解的才会进来
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
//这里只有是DeferredImportSelector的实现才走这里
//所以找启动类上的注解,只有@EnableAutoConfiguration里面有引入
//@Import(AutoConfigurationImportSelector.class)
//DeferredImportSelector 继承了 ImportSelector
if (selector instanceof DeferredImportSelector) {
//接下来走这里 ###
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
...//省略部分代码
}
- 接下来到
ConfigurationClassParser#handler
方法,到内部类DeferredImportSelectorHandler
//贴一下该类的两个方法
private class DeferredImportSelectorHandler {
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
//只有在process 也就是处理中的时候为null 本地变量锁的用法
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
//递归
handler.processGroupImports();
}
else {
//正常不会为null 添加到这个list
this.deferredImportSelectors.add(holder);
}
}
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
//根据已添加的ImportSelector的类进行回调 接下来走这里 ###
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
上面通过解析已经拿到所有用@Import引入并且实现了DeferredImportSelector的类集合
- 再次回到
ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)
//找到该该方法的最后一行代码
this.deferredImportSelectorHandler.process();
//到上面内部类DeferredImportSelectorHandler#process,接下来走这行代码
handler.processGroupImports();
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
//先看getImports() ###
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
//这里又是处理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);
}
});
}
}
ConfigurationClassParser#getImports()
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//获取需要自动加载的类 ###
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
//经过处理后 返回所需的自动装置的类
return this.group.selectImports();
}
- 这个group会到
AutoConfigurationImportSelector
的内部类AutoConfigurationGroup#process
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
//解析需要自动装配的类 接下来看怎么找到需要解析的类 ###
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
//保存 在下面的selectImports 进行处理后返回
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
//获取到自动装配的类的后续 等下就不贴了
@Override
public Iterable<Entry> selectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
//需要排除的classname
Set<String> allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
//需要自动装配的classname的list集合
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
//移除
processedConfigurations.removeAll(allExclusions);
//排序并封装
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
}
//getgetAutoConfigurationEntry -> getCandidateConfigurations
//到AutoConfigurationImportSelector
//通过classLoader获取指定key需要自动装配的类
List<String> configurations =
//getSpringFactoriesLoaderFactoryClass return EnableAutoConfiguration.class;
//这里的key也就是自动装配EnableAutoConfiguration类路径
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
//key明就是EnableAutoConfiguration类路径
//org.springframework.boot.autoconfigure.EnableAutoConfiguration
String factoryTypeName = factoryType.getName();
//这里从缓存中获取对应类加载器的自动装配的内容 然后再取出key的值 默认返回空list
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
- 接下来
SpringFactoriesLoader #loadSpringFactories
,获取所有需要自动装置的类存入缓存
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
//先从缓存获取
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
//String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
//从路径得知应该是去指定文件里面读取 接下来我们看下对应的文件
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
//保存到对应类加载器的map key是对应的类加载器
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
- 这里只引人了springboot包,所以找一下spring-boot-autoconfigure包目录下的META-INF/spring.factories的文件,找到对应的key
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
......
- 反正对应需要自动装配的类之后,接下来回到
ConfigurationClassParser#processGroupImports
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
//会继续走到扫描加载类 递归的做法 ###
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);
}
});
}
}
- 接下来回到
ConfigurationClassParser#processImports
,因为此时已经不是ImportSelector,找到这个else
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
//不是ImportSelector的实现类的走向
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//加载到本地Map存储
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
//processConfigurationClass最后
//存储到本地map
this.configurationClasses.put(configClass, configClass);
需要自动装配的类已经都存在本地的map中了,接下来应该就是晚容器中注册了
- 再回到
ConfigurationClassPostProcessor#processConfigBeanDefinitions
- 前面的代码其实都是在分析
parser.parse(candidates);
,接下来走到后面这行
parser.parse(candidates);
parser.validate();
//public Set<ConfigurationClass> getConfigurationClasses() {
// return this.configurationClasses.keySet();
// }
//取出存储需要注册的类 return this.configurationClasses.keySet();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// 取出reader 没有就创建
// 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());
}
//向容器注册
this.reader.loadBeanDefinitions(configClasses);
到这里,整个自动装配的流程就结束了,源码比较绕,需要很有耐心看
以上就是本章的全部内容了。
上一篇:SpringMvc源码分析第六弹 - 基于SpringMvc源码后的手写高仿版
下一篇:Springboot源码分析第二弹 - 自动配置实现
东隅已逝,桑榆非晚