最近突然对springboot环境下webmvc的初始化感兴趣,于是就写了这篇文章记录一下这个过程的一部分作为笔记,方便以后忘记的时候查阅。
首先,从springboot启动的类开始跟起。
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(EurekaApplication.class, args);
}
}
run方法里面是一系列对spring容器的操作:创建applicationContext,预处理context,刷新context,以及刷新完成后事件的发布。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
进入createApplicationContext方法跟进,发现方法内会根据是否web环境,通过反射的方式来实例化AnnotationConfigEmbeddedWebApplicationContext或普通的AnnotationConfigApplicationContext。
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
再看web环境下创建的AnnotationConfigEmbeddedWebApplicationContext类,发现构造方法里面创建了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner对象。接着打开AnnotatedBeanDefinitionReader类,发现它的构造函数里会调用AnnotationConfigUtils的AnnotationConfigProcessors方法。
public AnnotationConfigEmbeddedWebApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
跟进注册处理器的方法registerAnnotationConfigProcessors,方法里面会注册一系列的后置处理器,这里只需要重点关注ConfigurationClassPostProcessor这个处理器。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//主要关注这个处理器
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//其他后置处理器的注册,跟 ConfigurationClassPostProcessor 的注册类似,省略后面的代码
......
}
接着,跟进refreshContext方法,实际上调用的是spring容器初始化(AbstractApplicationContext.refresh())那一套。
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
在spring容器初始化过程中,会创建BeanFactory,并对beanFactoryPostProcessor进行调用。在invokeBeanFactoryPostProcessors方法里,先对beanFactory进行判断,如果是BeanDefinitionRegistry,会
对注册了的BeanDefinitionRegistryPostProcessor进行调用处理。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//对beanFactoryPostProcessor进行调用
invokeBeanFactoryPostProcessors(beanFactory);
//后续代码省略
......
}
}
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<String>();
//这里对beanFactory进行拉了判断
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
// 获取BeanDefinitionRegistryPostProcessor类的beanName
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);
//这里进一步对待处理的BeanDefinitionRegistryPostProcessor列表进行调用处理
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
//后续代码省略
......
}
处理这些待处理的BeanDefinitionRegistryPostProcessor,实际上是调用它们的postProcessBeanDefinitionRegistry方法。这个时候,上面提到的ConfigurationClassPostProcessor就开始出场了,这个类也是一个BeanDefinitionRegistryPostProcessor类,所以也会调用这个方法。
在方法里面,进行一些校验后,最终调用了processConfigBeanDefinitions方法。
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);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//最终调用这个方法
processConfigBeanDefinitions(registry);
}
在processConfigBeanDefinitions方法里,做的一系列操作如下:
- 获取注册中心里,可能是ConfigurationClass的BeanDefinition,记为配置类候选人。
- 新建一个解析配置类的解析器ConfigurationClassParser对象。
- 对配置类候选人进行解析,解析出真正的配置类。
- 加载这些配置类的beanDefinition。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//1.判断是配置类候选人,添加到候选人队列
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//省略中间代码
......
//2.新建配置类解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
//对候选人解析,获取真正的配置类
do {
//3.执行解析操作
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
//省略中间代码
......
//4.加载配置类的beanDefinition
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//省略中间代码
......
}
while (!candidates.isEmpty());
}
接下来看一下解析器执行解析的方法parse,方法里有两个步骤:
- 对每个候选人进行解析。
- 处理需要延期处理的importSelector(延期处理是processDeferred字面上的意思,实际上就是"先放入集合,最后再处理")。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
//遍历"候选人",对候选人进行解析
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
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);
}
}
//处理延期处理的selectors
processDeferredImportSelectors();
}
进入parse方法,发现里面调用了processConfigurationClass方法。在这个方法里,先是把已经处理过的配置类集合里的配置类和作为参数传入的配置类(即当前解析的配置类)进行匹配,如果没有匹配成功,就会进行真正的配置类解析工作,执行doProcessConfigurationClass方法,而如果匹配成功的逻辑,此处不做详解,有需要可以自行跟踪一下。
//三个parse方法调用的都是processConfigurationClass方法
protected final void parse(String className, String beanName) throws IOException {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//判断当前需要解析的配置类是否有解析过
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
//执行真正的解析操作,这里返回的会是当前配置类的父类,然后对父类再次执行真正的解析操作,一直解析到
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
在 doProcessConfigurationClass 方法里,会有如下处理步骤:
- 处理当前配置类的内部类。
- 处理@PropertySource注解。
- 处理@ComponentScan注解。
- 处理@Import注解。
- 处理@ImportResource注解。
- 处理bean方法。
- 处理配置类的接口。
- 处理父类。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
// 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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 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
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) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(
holder.getBeanDefinition(), this.metadataReaderFactory)) {
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
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);
}
}
// 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.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;
}
这里只详细查看第四步,对@Import注解的处理。
首先调用的是getImports方法,方法里面调用的是collectImports方法,该方法实际做的事是由下往上遍历注解(遍历注解的注解),并将@Import注解引入的类存入队列中。接着把引入类队列作为参数传入processImports方法里进行处理。在processImports方法里,会对传入的引入类集合进行遍历,如果是ImportSelector类则会先实例化,然后判断如果还是DeferredImportSelector的实例,就会放入 延期处理队列 里。
//获取 Import注解引入的类
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<SourceClass>();
Set<SourceClass> visited = new LinkedHashSet<SourceClass>();
collectImports(sourceClass, imports, visited);
return imports;
}
//由下往上遍历注解,找出Import注解引入的类
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
//处理Import注解引入的类
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
//省略部分代码
......
//遍历引入的类
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
//如果是DeferredImportSelector实例,加入延期处理队列
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
//省略部分代码
......
}
//省略部分代码
......
}
到现在为止,已经把引入的延期处理类给收集起来了,回到前面处理延期队列的方法processDeferredImportSelectors。在方法里面,会遍历importSelector,调用selector的selectImports方法获取引用类的类名,并对这些引入类执行前面的引用类处理操作processImports。
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
//执行selectImports方法获取引入的类的类名
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
//处理引入类
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}
在调试的过程中,会有好几个ImportSelector,这里只看这个EnableAutoConfigurationImportSelector的selectImports方法。点进方法继续跟踪,发现调用的是父类的selectImports方法。
1.在该方法内部,先调用了AutoConfigurationMetadataLoader类的loadMetadata方法,方法里将META-INF/spring-autoconfigure-metadata.properties的属性文件加载进来并封装在一个对象中并返回。
2.返回到selectImports方法,加载完属性文件后,调用了getCandidateConfigurations方法,在这个方法里面,首先是通过getSpringFactoriesLoaderFactoryClass方法获取到了EnableAutoConfiguration类对象,然后再调用SpringFactoriesLoader的loadFactoryNames方法,通过加载类路径下的META-INF/spring.factories属性文件,获取到EnableAutoConfiguration类的实现类(使用类)的类名。
3.返回到selectImports方法,在获取到步骤2获取到的类名后,对这些类名进行了一些过滤,此处不再进一步跟踪。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
//步骤1
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//步骤2
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//步骤3,代码省略
......
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
//其中 PATH 为类变量"META-INF/spring-autoconfigure-metadata.properties"
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path));
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils
.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException(
"Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
//其中 FACTORIES_RESOURCE_LOCATION 为类变量"META-INF/spring.factories"
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
返回到延迟处理方法内,在收集完引入类后,接下里就是调用processImports对这些引入类进行处理了。上面只是讲了判断引入类是ImportSelector的情况,这里跟踪引入类不是ImportSelector的实现类,也不是ImportBeanDefinitionRegistrar实现类的情况。
在众多的引入类中,这里只拿WebMvcAutoConfiguration这个类来跟进,因为这个类涉及到这次源码跟踪的目标"RequestMappingHandlerMapping"。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
//省略代码
......
if (candidate.isAssignable(ImportSelector.class)) {
//省略代码
......
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
//省略代码
......
}
else {
// 作为一个配置类进行处理
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
处理配置类的方法processConfigurationClass在上面已经跟踪过了,就是重复一系列的步骤,这个时候不把注意力放在这些步骤上,而是把注意力放在WebMvcAutoConfiguration类上。
这个类有好几个内部类,其中的EnableWebMvcConfiguration是要关注的类。在处理配置类的步骤中,第一步就是先对内部类进行处理,即processMemberClasses这个方法,跟进这个方法,发现是对内部类进行遍历比较,并判断这些内部类是否为配置类,如果判断符合配置类条件,就会把这个内部类封装成配置类并调用processConfigurationClass方法进行处理。而EnableWebMvcConfiguration这个类还确实是配置类。
接着把注意力放在EnableWebMvcConfiguration类上,没有发现类变量,但是有好几个@Bean注解的方法,而且RequestMappingHandlerMapping就由其中一个Bean方法创建。在处理配置类的步骤中,retrieveBeanMethodMetadata方法就是处理@Bean方法的,这里简单的理解为将@Bean方法采集并将方法信息封装为一个对象存入set集合中,并添加到配置类的beanMethods集合中。
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
//省略部分代码
......
//@Configuration注解表明了这是一个配置类
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
//省略部分代码
......
//这是一个BeanMethod
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping();
}
//省略部分代码
......
}
}
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass){
//省略部分代码
......
//采集@Bean method并添加到配置类的beanMethods set里
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//省略部分代码
......
}
final class ConfigurationClass {
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
//省略部分代码
......
public void addBeanMethod(BeanMethod method) {
this.beanMethods.add(method);
}
//省略部分代码
......
}
接着往下执行代码,就把整个配置类解析器ConfigurationClassParser的解析方法parse执行完了,解析完配置类后,接下来就是执行BeanDefinitionReader的loadBeanDefinitions方法来注册解析出来的配置类中包含的bean的定义信息了。
loadBeanDefinitions方法遍历传入的配置类,并调用loadBeanDefinitionsForConfigurationClass方法加载每个配置类。在方法里面,就会遍历配置类的beanMethods集合,并调用loadBeanDefinitionsForBeanMethod方法来加载bean方法的注册信息,方法内最终调用BeanDefinitionRegistry的registerBeanDefinition来注册Bean。
所以BeanDefinitionReader的loadBeanDefinitions方法执行完毕后,RequestMappingHandlerMapping就已经被注册进容器内了,而这个Bean的实例化和初始化就会在ApplicationContext的finishBeanFactoryInitialization()方法里进行了。
到此RequestMappingHandlerMapping的实例化就算完成了。