前言
前面的文章描述了Application对应Bean的创建,本篇将阐述spring boot中bean的创建过程
refresh
首先来看SpringApplication#run方法中refresh()方法
[html] view plain copy
- // Refresh the context
- refresh(context);
调用的是AbstractApplicationContext中的refresh方法
[html] view plain copy
- protected void refresh(ApplicationContext applicationContext) {
- Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
- ((AbstractApplicationContext) applicationContext).refresh();
- }
方法定义如下:
[html] view plain copy
- 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.
- invokeBeanFactoryPostProcessors(beanFactory);
- // Register bean processors that intercept bean creation.
- registerBeanPostProcessors(beanFactory);
- // Initialize message source for this context.
- initMessageSource();
- // Initialize event multicaster for this context.
- initApplicationEventMulticaster();
- // Initialize other special beans in specific context subclasses.
- onRefresh();
- // Check for listener beans and register them.
- registerListeners();
- // Instantiate all remaining (non-lazy-init) singletons.
- finishBeanFactoryInitialization(beanFactory);
- // Last step: publish corresponding event.
- finishRefresh();
- }
- catch (BeansException ex) {
- logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
- // Destroy already created singletons to avoid dangling resources.
- destroyBeans();
- // Reset 'active' flag.
- cancelRefresh(ex);
- // Propagate exception to caller.
- throw ex;
- }
- }
- }
该方法中涉及的过程非常多,需要一步步来分析
获取BeanFactory
[html] view plain copy
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
通过前面的文章应该知道对应的BeanFactory为DefaultListableBeanFactory
直奔主题来看如下方法
[html] view plain copy
- invokeBeanFactoryPostProcessors(beanFactory);
[html] view plain copy
- protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
- PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
- }
首先来看getBeanFactoryPostProcessors(),其对应值为:ConfigurationWarningsApplicationContextInitializer$ConfigurationWarningsPostProcessor、PropertySourceOrderingPostProcessor
ConfigurationWarningsApplicationContextInitializer是在ConfigurationWarningsApplicationContextInitializer中执行
[html] view plain copy
- public void initialize(ConfigurableApplicationContext context) {
- context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(
- getChecks()));
- }
添加
PropertySourceOrderingPostProcessor是在ConfigFileApplicationListener执行
[html] view plain copy
- protected void addPostProcessors(ConfigurableApplicationContext context) {
- context.addBeanFactoryPostProcessor(new PropertySourceOrderingPostProcessor(
- context));
- }
添加
来看invokeBeanFactoryPostProcessors方法
[html] view plain copy
- public static void invokeBeanFactoryPostProcessors(
- ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
- // Invoke BeanDefinitionRegistryPostProcessors first, if any.
- Set<String> processedBeans = new HashSet<String>();
- if (beanFactory instanceof BeanDefinitionRegistry) {
- ...//处理后处理器
- String[] postProcessorNames =
- beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
- // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
- List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
- for (String ppName : postProcessorNames) {
- if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
- priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
- processedBeans.add(ppName);
- }
- }
- OrderComparator.sort(priorityOrderedPostProcessors);
- registryPostProcessors.addAll(priorityOrderedPostProcessors);
- invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
- // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
- postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
- List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
- for (String ppName : postProcessorNames) {
- if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
- orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
- processedBeans.add(ppName);
- }
- }
- OrderComparator.sort(orderedPostProcessors);
- registryPostProcessors.addAll(orderedPostProcessors);
- invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
- // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
- boolean reiterate = true;
- while (reiterate) {
- reiterate = false;
- postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
- for (String ppName : postProcessorNames) {
- if (!processedBeans.contains(ppName)) {
- BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
- registryPostProcessors.add(pp);
- processedBeans.add(ppName);
- pp.postProcessBeanDefinitionRegistry(registry);
- reiterate = true;
- }
- }
- }
- // Now, invoke the postProcessBeanFactory callback of all processors handled so far 执行后处理器
- invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
- invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
- }
[html] view plain copy
- String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
按照bean的类型获取类型为BeanDefinitionRegistryPostProcessor的bean,这里获取到的bean名称为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor;对应的Class为ConfigurationClassPostProcessor
在前面文章中创建上下文的时候beanfactory创建了该bean。
经过排序后执行如下方法
[html] view plain copy
- invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
[html] view plain copy
- private static void invokeBeanDefinitionRegistryPostProcessors(
- Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
- for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
- postProcessor.postProcessBeanDefinitionRegistry(registry);
- }
- }
实际调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
[html] view plain copy
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
- ...//注册若干bean
- processConfigBeanDefinitions(registry);
- }
processConfigBeanDefinitions(registry)如下:
[html] view plain copy
- public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
- Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<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)) {
- configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
- }
- }
- // Return immediately if no @Configuration classes were found
- if (configCandidates.isEmpty()) {
- return;
- }
- // Detect any custom bean name generation strategy supplied through the enclosing application context
- SingletonBeanRegistry singletonRegistry = null;
- if (registry instanceof SingletonBeanRegistry) {
- singletonRegistry = (SingletonBeanRegistry) registry;
- if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
- BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
- this.componentScanBeanNameGenerator = generator;
- this.importBeanNameGenerator = generator;
- }
- }
- // Parse each @Configuration class
- ConfigurationClassParser parser = new ConfigurationClassParser(
- this.metadataReaderFactory, this.problemReporter, this.environment,
- this.resourceLoader, this.componentScanBeanNameGenerator, registry);
- Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
- do {
- parser.parse(configCandidates);
- parser.validate();
- Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(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.problemReporter, this.metadataReaderFactory, this.resourceLoader, this.environment,
- this.importBeanNameGenerator, parser.getImportRegistry());
- }
- this.reader.loadBeanDefinitions(configClasses);
- alreadyParsed.addAll(configClasses);
- configCandidates.clear();
- if (registry.getBeanDefinitionCount() > candidateNames.length) {
- String[] newCandidateNames = registry.getBeanDefinitionNames();
- Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
- Set<String> alreadyParsedClasses = new HashSet<String>();
- for (ConfigurationClass configurationClass : alreadyParsed) {
- alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
- }
- for (String candidateName : newCandidateNames) {
- if (!oldCandidateNames.contains(candidateName)) {
- BeanDefinition beanDef = registry.getBeanDefinition(candidateName);
- if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) &&
- !alreadyParsedClasses.contains(beanDef.getBeanClassName())) {
- configCandidates.add(new BeanDefinitionHolder(beanDef, candidateName));
- }
- }
- }
- candidateNames = newCandidateNames;
- }
- }
- while (!configCandidates.isEmpty());
- // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
- if (singletonRegistry != null) {
- if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
- singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
- }
- }
- if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
- ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
- }
- }
又是一段很长的代码
[html] view plain copy
- String[] candidateNames = registry.getBeanDefinitionNames();
获取已经注册的bean名称,其信息为:
这里看到上一篇中创建的Application对应bean
[html] view plain copy
- 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)) {
- configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
- }
- }
判断对应bean是否为配置文件bean(包含Configuration注解),经过筛选只有Application对应bean满足条件
[html] view plain copy
- ConfigurationClassParser parser = new ConfigurationClassParser(
- this.metadataReaderFactory, this.problemReporter, this.environment,
- this.resourceLoader, this.componentScanBeanNameGenerator, registry);
该代码构造了Configuration类解析器
执行
[html] view plain copy
- parser.parse(configCandidates);
[html] view plain copy
- 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 (Exception ex) {
- throw new BeanDefinitionStoreException(
- "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
- }
- }
- processDeferredImportSelectors();
- }
调用
[html] view plain copy
- parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
最终调用
[html] view plain copy
- 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);
- }
首先判断该bean是否被跳过(该部分代码上一篇已说明),然后对Class进行包装,调用sourceClass = doProcessConfigurationClass(configClass,sourceClass)处理Application类
解析Configuration注解
[html] view plain copy
- 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
- AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class);
- if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
- // 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 necessary
- 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("value");
- 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 = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
- for (MethodMetadata methodMetadata : beanMethods) {
- configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
- }
- // 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;
- }
到这里就看到了如何去解析Application类
[html] view plain copy
- processMemberClasses(configClass, sourceClass);
处理其中内部类,解析内部类的过程和外部类相似,因此继续看下面的代码
处理PropertySource注解
[html] view plain copy
- // 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");
- }
- }<pre name="code" class="html">
[html] view plain copy
其核心操作:
[html] view plain copy
- private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
- String name = propertySource.getString("name");
- String[] locations = propertySource.getStringArray("value");
- boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
- Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
- for (String location : locations) {
- try {
- String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
- Resource resource = this.resourceLoader.getResource(resolvedLocation);
- ResourcePropertySource rps = (StringUtils.hasText(name) ?
- new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource));
- addPropertySource(rps);
- }
- catch (IllegalArgumentException ex) {
- // from resolveRequiredPlaceholders
- if (!ignoreResourceNotFound) {
- throw ex;
- }
- }
- catch (FileNotFoundException ex) {
- // from ResourcePropertySource constructor
- if (!ignoreResourceNotFound) {
- throw ex;
- }
- }
- }
- }
通过注解中的信息获取资源信息,然后添加到MutablePropertySourcespropertySources = ((ConfigurableEnvironment)this.environment).getPropertySources()中,该内容前面已有讲述
解析ComponentScan注解
[html] view plain copy
- // Process any @ComponentScan annotations
- AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class);
- if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
- // 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 necessary
- for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
- if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
- parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
- }
- }
- }
ComponentScan注解的作用大家都明白,扫描执行路径下bean信息,那么具体是如何实现的?需要跟进去看代码,调用
[html] view plain copy
- Set<BeanDefinitionHolder> scannedBeanDefinitions =
- this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
[html] view plain copy
- public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
- ...//通过注解中的信息设置扫描器的参数信息
- return scanner.doScan(StringUtils.toStringArray(basePackages));
- }
代码中忽略了扫描器对应的参数信息,直接看doScan方法
[html] view plain copy
- protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
- Assert.notEmpty(basePackages, "At least one base package must be specified");
- Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
- for (String basePackage : basePackages) {
- 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) {
- 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;
- }
遍历basePackages信息,
[html] view plain copy
- Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
查询类路径下申明的组件信息,
[html] view plain copy
- public Set<BeanDefinition> findCandidateComponents(String basePackage) {
- Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
- try {
- String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
- resolveBasePackage(basePackage) + "/" + this.resourcePattern;
- Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
- boolean traceEnabled = logger.isTraceEnabled();
- boolean debugEnabled = logger.isDebugEnabled();
- for (Resource resource : resources) {
- if (traceEnabled) {
- logger.trace("Scanning " + resource);
- }
- if (resource.isReadable()) {
- try {
- MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
- if (isCandidateComponent(metadataReader)) {
- ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
- sbd.setResource(resource);
- sbd.setSource(resource);
- if (isCandidateComponent(sbd)) {
- if (debugEnabled) {
- logger.debug("Identified candidate component class: " + resource);
- }
- candidates.add(sbd);
- }
- else {
- if (debugEnabled) {
- logger.debug("Ignored because not a concrete top-level class: " + resource);
- }
- }
- }
- else {
- if (traceEnabled) {
- logger.trace("Ignored because not matching any filter: " + resource);
- }
- }
- }
- catch (Throwable ex) {
- throw new BeanDefinitionStoreException(
- "Failed to read candidate component class: " + resource, ex);
- }
- }
- else {
- if (traceEnabled) {
- logger.trace("Ignored because not readable: " + resource);
- }
- }
- }
- }
- catch (IOException ex) {
- throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
- }
- return candidates;
- }
看
[html] view plain copy
- Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
[html] view plain copy
- public Resource[] getResources(String locationPattern) throws IOException {
- Assert.notNull(locationPattern, "Location pattern must not be null");
- if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
- // a class path resource (multiple resources for same name possible)
- if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
- // a class path resource pattern
- return findPathMatchingResources(locationPattern);
- }
- else {
- // all class path resources with the given name
- return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
- }
- }
- else {
- // Only look for a pattern after a prefix here
- // (to not get fooled by a pattern symbol in a strange prefix).
- int prefixEnd = locationPattern.indexOf(":") + 1;
- if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
- // a file pattern
- return findPathMatchingResources(locationPattern);
- }
- else {
- // a single resource with the given name
- return new Resource[] {getResourceLoader().getResource(locationPattern)};
- }
- }
- }
解析路径信息,这里spring有自己的一套继续规则,通过findPathMatchingResources()检索到指定类路径下所有的*.class文件,然后调用findAllClassPathResources解析Class文件
[html] view plain copy
- protected Resource[] findAllClassPathResources(String location) throws IOException {
- String path = location;
- if (path.startsWith("/")) {
- path = path.substring(1);
- }
- Set<Resource> result = doFindAllClassPathResources(path);
- return result.toArray(new Resource[result.size()]);
- }
[html] view plain copy
- protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
- Set<Resource> result = new LinkedHashSet<Resource>(16);
- ClassLoader cl = getClassLoader();
- Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
- while (resourceUrls.hasMoreElements()) {
- URL url = resourceUrls.nextElement();
- result.add(convertClassLoaderURL(url));
- }
- if ("".equals(path)) {
- // The above result is likely to be incomplete, i.e. only containing file system references.
- // We need to have pointers to each of the jar files on the classpath as well...
- addAllClassLoaderJarRoots(cl, result);
- }
- return result;
- }
通过上面的代码可以发现,在获取到path路径以后spring采用类加载器获取指定Class文件对应的资源信息
获取完资源信息后调用
[html] view plain copy
- MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
解析资源信息对应的元数据
[html] view plain copy
- if (isCandidateComponent(metadataReader)) {
- ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
- sbd.setResource(resource);
- sbd.setSource(resource);
- if (isCandidateComponent(sbd)) {
- if (debugEnabled) {
- logger.debug("Identified candidate component class: " + resource);
- }
- candidates.add(sbd);
- }
- else {
- if (debugEnabled) {
- logger.debug("Ignored because not a concrete top-level class: " + resource);
- }
- }
- }
- else {
- if (traceEnabled) {
- logger.trace("Ignored because not matching any filter: " + resource);
- }
- }
如果存在Componment注解修饰的Class文件则加入到BeanDefinition集合中返回。
回到调用扫描bean处
[html] view plain copy
- for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
- if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
- parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
- }
- }
遍历扫描到的bean信息,如果为配置bean,则执行parse方法,该方法调用processConfigurationClass,形成一个递归的操作。
解析Import注解
[html] view plain copy
- processImports(configClass, sourceClass, getImports(sourceClass), true);
处理import注解,该注解在spring boot中使用非常频繁
[html] view plain copy
- private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
- Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
- ...
- this.importStack.push(configClass);
- try {
- 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 = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
- invokeAwareMethods(selector);
- if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
- this.deferredImportSelectors.add(
- new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
- }
- else {
- String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
- Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
- processImports(configClass, currentSourceClass, importSourceClasses, false);
- }
- }
- else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
- // Candidate class is an ImportBeanDefinitionRegistrar ->
- // delegate to it to register additional bean definitions
- Class<?> candidateClass = candidate.loadClass();
- ImportBeanDefinitionRegistrar registrar =
- BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
- invokeAwareMethods(registrar);
- configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
- }
- else {
- // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
- // process it as an @Configuration class
- this.importStack.registerImport(
- currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
- processConfigurationClass(candidate.asConfigClass(configClass));
- }
- }
- }
- catch (BeanDefinitionStoreException ex) {
- throw ex;
- }
- catch (Exception ex) {
- throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
- configClass.getMetadata().getClassName() + "]", ex);
- }
- finally {
- this.importStack.pop();
- }
- }
- }
如果Import注解中Class为ImportSelector子类,通过invokeAwareMethods(selector)设置aware值,如果类型为DeferredImportSelector则添加到deferredImportSelectors集合中,待前面的parser.parse(configCandidates)
方法中processDeferredImportSelectors()处理;如果不是,则执行selectImports方法,将获取到的结果递归调用processImports,解析selectImports得到的结果
如果Import注解中Class为ImportBeanDefinitionRegistrar子类,则添加到importBeanDefinitionRegistrars中,注意该部分的数据在执行完parser.parse(configCandidates)后调用this.reader.loadBeanDefinitions(configClasses)解析
否则执行配置信息的解析操作。
解析ImportResource注解
[html] view plain copy
- // Process any @ImportResource annotations
- if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
- AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
- String[] resources = importResource.getStringArray("value");
- Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
- for (String resource : resources) {
- String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
- configClass.addImportedResource(resolvedResource, readerClass);
- }
- }
解析Bean注解
[html] view plain copy
- Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
- for (MethodMetadata methodMetadata : beanMethods) {
- configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
- }
上面这两个注解相对来讲要简单一些,至此bean的解析完成,这里面涉及到多重递归,首先理清楚一条线才能把代码看明白。