其他分享
首页 > 其他分享> > 7.refresh-invokeBeanFactoryPostProcessor方法解析(中)

7.refresh-invokeBeanFactoryPostProcessor方法解析(中)

作者:互联网

【接上文】

processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

ConfigurationClassParser#processImports

//在解析时,入栈,解析结束后,出栈,通过检查栈中是否有当前类,判断是否有循环依赖
private final ImportStack importStack = new ImportStack();

//记录所有的ImportBeanDefinitionRegistrar
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>();

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {
    if (importCandidates.isEmpty()) {
        return;
    }
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    } else {
        //在解析时,入栈,解析结束后,出栈,通过检查栈中是否有当前类,判断是否有循环依赖
        this.importStack.push(configClass);
        try {
            for (SourceClass candidate : importCandidates) {
                //处理@ImportSelector
                if (candidate.isAssignable(ImportSelector.class)) {
                    //处理实现了ImportSelector接口的类
                    ...具体过程下文分析,看到整体脉络即可
                }
                //处理实现了ImportBeanDefinitionRegistrar接口的类
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    //处理实现了ImportBeanDefinitionRegistrar接口的类
                    ...具体过程下文分析,看到整体脉络即可
                }
                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), exclusionFilter);
                }
            }
        } catch (BeanDefinitionStoreException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configClass.getMetadata().getClassName() + "]", ex);
        } finally {
            this.importStack.pop();
        }
    }
}

ConfigurationClassParser#getImports

/**
 * Returns {@code @Import} class, considering all meta-annotations.
 */
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    Set<SourceClass> imports = new LinkedHashSet<>();
    Set<SourceClass> visited = new LinkedHashSet<>();
    //递归查询所有注解以及注解的注解是否包含@Import
    collectImports(sourceClass, imports, visited);
    return imports;
}

/**
 * Recursively collect all declared {@code @Import} values. Unlike most
 * meta-annotations it is valid to have several {@code @Import}s declared with
 * different values; the usual process of returning values from the first
 * meta-annotation on a class is not sufficient.
 * <p>For example, it is common for a {@code @Configuration} class to declare direct
 * {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
 * annotation.
 * @param sourceClass the class to search
 * @param imports the imports collected so far
 * @param visited used to track visited classes to prevent infinite recursion
 * @throws IOException if there is any problem reading metadata from the named class
 */
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
        throws IOException {
    //记录是否已经扫描过这个类,如果扫描过就不重复添加,防止重复或者死循环
    if (visited.add(sourceClass)) {
        for (SourceClass annotation : sourceClass.getAnnotations()) {
            String annName = annotation.getMetadata().getClassName();
            //对于非@Import注解,递归查找其内部是否包含@Import注解
            if (!annName.equals(Import.class.getName())) {
                collectImports(annotation, imports, visited);
            }
        }
        //添加@Import注解里面的所有配置类
        imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    }
}

通过getImports方法,采集相关的@Import里面的类。

对ImportSelector的处理

//处理@ImportSelector
if (candidate.isAssignable(ImportSelector.class)) {
    //处理@ImportSelector
    // 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,则用deferredImportSelectorHandler处理
    if (selector instanceof DeferredImportSelector) {
        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
    }
    else {
        //迭代进行selectImports中bean的解析
        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
    }
}

获取ImportSelect实例的时候用到了ParserStregyUtils这个类,大概看下。

package org.springframework.context.annotation;
...省略引包代码
/**
 * Common delegate code for the handling of parser strategies, e.g.
 * {@code TypeFilter}, {@code ImportSelector}, {@code ImportBeanDefinitionRegistrar}
 * 处理解析策略的通用代理类
 */
abstract class ParserStrategyUtils {

	/**
	 * Instantiate a class using an appropriate constructor and return the new
	 * instance as the specified assignable type. The returned instance will
	 * have {@link BeanClassLoaderAware}, {@link BeanFactoryAware},
	 * {@link EnvironmentAware}, and {@link ResourceLoaderAware} contracts
	 * invoked if they are implemented by the given object.
     * 使用合适的构造方法实例化一个类,返回的实例如果实现了aware接口将会调用对应的set方法。
	 * @since 5.2
	 */
	@SuppressWarnings("unchecked")
	static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo, Environment environment,
			ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {

		Assert.notNull(clazz, "Class must not be null");
		Assert.isAssignable(assignableTo, clazz);
		if (clazz.isInterface()) {
			throw new BeanInstantiationException(clazz, "Specified class is an interface");
		}
		ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ?
				((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader());
		T instance = (T) createInstance(clazz, environment, resourceLoader, registry, classLoader);
        //注入aware接口的相关属性
		ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader);
		return instance;
	}

	private static Object createInstance(Class<?> clazz, Environment environment,
			ResourceLoader resourceLoader, BeanDefinitionRegistry registry,
			@Nullable ClassLoader classLoader) {
        //取构造方法
		Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        //存在带参构造方法  
        //这里看了下大部分的ImportSelector的实现类都是没有带参构造方法的
		if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
			try {
				Constructor<?> constructor = constructors[0];
                //解析参数类型并设置对应的值
				Object[] args = resolveArgs(constructor.getParameterTypes(),
						environment, resourceLoader, registry, classLoader);
				return BeanUtils.instantiateClass(constructor, args);
			}
			catch (Exception ex) {
				throw new BeanInstantiationException(clazz, "No suitable constructor found", ex);
			}
		}
		return BeanUtils.instantiateClass(clazz);
	}
    
    //设置参数
	private static Object[] resolveArgs(Class<?>[] parameterTypes,
			Environment environment, ResourceLoader resourceLoader,
			BeanDefinitionRegistry registry, @Nullable ClassLoader classLoader) {

			Object[] parameters = new Object[parameterTypes.length];
			for (int i = 0; i < parameterTypes.length; i++) {
				parameters[i] = resolveParameter(parameterTypes[i], environment,
						resourceLoader, registry, classLoader);
			}
			return parameters;
	}
    
    /**
    * 根据参数类型返回对应的值
    * Environment
    * ResourceLoader
    * Registry
    * ClassLoader
    */
	@Nullable
	private static Object resolveParameter(Class<?> parameterType,
			Environment environment, ResourceLoader resourceLoader,
			BeanDefinitionRegistry registry, @Nullable ClassLoader classLoader) {

		if (parameterType == Environment.class) {
			return environment;
		}
		if (parameterType == ResourceLoader.class) {
			return resourceLoader;
		}
		if (parameterType == BeanFactory.class) {
			return (registry instanceof BeanFactory ? registry : null);
		}
		if (parameterType == ClassLoader.class) {
			return classLoader;
		}
		throw new IllegalStateException("Illegal method parameter type: " + parameterType.getName());
	}
    
    /**
    * 如果实现了aware接口的子接口则设置相应的属性参数
    */
	private static void invokeAwareMethods(Object parserStrategyBean, Environment environment,
			ResourceLoader resourceLoader, BeanDefinitionRegistry registry, @Nullable ClassLoader classLoader) {

		if (parserStrategyBean instanceof Aware) {
			if (parserStrategyBean instanceof BeanClassLoaderAware && classLoader != null) {
				((BeanClassLoaderAware) parserStrategyBean).setBeanClassLoader(classLoader);
			}
			if (parserStrategyBean instanceof BeanFactoryAware && registry instanceof BeanFactory) {
				((BeanFactoryAware) parserStrategyBean).setBeanFactory((BeanFactory) registry);
			}
			if (parserStrategyBean instanceof EnvironmentAware) {
				((EnvironmentAware) parserStrategyBean).setEnvironment(environment);
			}
			if (parserStrategyBean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) parserStrategyBean).setResourceLoader(resourceLoader);
			}
		}
	}

}

根据上面源码的分析,我们大致捋一下@ImportSelector的解析流程
0. 获取到@Import和@Imports中的value 进行遍历

  1. @Import中的value指定的类如果实现了ImportSelector 则继续解析@SelectImports中的bean A
  2. @Import中的value指定的类如果实现了DeferedImportSelector 则交给deferedImportSelectorHandler进行处理 B
  3. 如果@Import中的value指定的类不满足1 和 2 则作为配置类解析成bean
  4. 1中的A如果满足1 则继续迭代1 如果满足2 则继续迭代2 如果都不满足 则进行3

解析@Import的时候还有个分支就是继承了ImportBeanDefinitionRegistrar

// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
        ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

这个的处理就比较简单了,先调用ParserStrategyUtils.instantiateClass实例化然后直接加入到configClass的ImportBeanDefinitionRegistrar集合中,后续使用。

再补充下DeferedImportSelector实现类的处理源码分析。
入口在ConfigurationClassParser#577-579

//handler定义
private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
if (selector instanceof DeferredImportSelector) {
    this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}

看下DeferredImportSelectorHandler的handle方法做了什么事情。

private class DeferredImportSelectorHandler {

    @Nullable
    private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
    
    /**
     * Handle the specified {@link DeferredImportSelector}. If deferred import
     * selectors are being collected, this registers this instance to the list. If
     * they are being processed, the {@link DeferredImportSelector} is also processed
     * immediately according to its {@link DeferredImportSelector.Group}.
     * @param configClass the source configuration class
     * @param importSelector the selector to handle
     */
    public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
        DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
        //通过@Import进到这个handle方法的  deferredImportSelectors 一定是new出来的 不走if分支
        if (this.deferredImportSelectors == null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            handler.register(holder);
            handler.processGroupImports();
        }
        else {
            //这里只是简单的把holder加入到deferredImportSelectors里面
            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);
                handler.processGroupImports();
            }
        }
        finally {
            this.deferredImportSelectors = new ArrayList<>();
        }
    }
}

可以看到handle方法并没有真正的处理@DeferedImportSelector,并没有调用process方法,process方法究竟是何时调用的呢?
还记得我们解析注解的入口方法吗?就是在那个方法的最后调用的,如下图:
ConfigurationClassParser#193
process方法调用位置
看来是先放到一个list中缓存起来等到所有的都解析完了再解析这部分内容,这也是ImportSelector和DeferedImportSelector区别的体现,也就是ImportSelector会优先解析注册,
DeferedImportSelector是在所有注解都解析完以后才进行的。

到此@Import流程的解析就完成了。

【小结】

整个@Import的解析流程就是

  1. 获取到@Import和@Imports中的value 进行遍历
  2. @Import中的value指定的类如果实现了ImportSelector 则先实例化然后继续解析@SelectImports中的bean A
  3. @Import中的value指定的类如果实现了DeferedImportSelector 则交给deferedImportSelectorHandler进行处理 B(放到一个list中,parse解析完成后再调用)
  4. @Import中的value指定的类如果实现了ImportBeanDefinitionRegistrar 则加入到configClass的ImportBeanDefinitionRegistrar集合中,后续使用。
  5. 如果123都不满足则作为配置类进行解析, 也就是调用processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
    对于1中解析出来的bean再进行判断 迭代走123的流程

标签:configClass,invokeBeanFactoryPostProcessor,refresh,ImportSelector,new,Import,解析,
来源: https://blog.csdn.net/u010361276/article/details/120502610