【接上文】
- @Import
ConfigurationClassParser#311
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 进行遍历
- @Import中的value指定的类如果实现了ImportSelector 则继续解析@SelectImports中的bean A
- @Import中的value指定的类如果实现了DeferedImportSelector 则交给deferedImportSelectorHandler进行处理 B
- 如果@Import中的value指定的类不满足1 和 2 则作为配置类解析成bean
- 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
看来是先放到一个list中缓存起来等到所有的都解析完了再解析这部分内容,这也是ImportSelector和DeferedImportSelector区别的体现,也就是ImportSelector会优先解析注册,
DeferedImportSelector是在所有注解都解析完以后才进行的。
到此@Import流程的解析就完成了。
【小结】
整个@Import的解析流程就是
- 获取到@Import和@Imports中的value 进行遍历
- @Import中的value指定的类如果实现了ImportSelector 则先实例化然后继续解析@SelectImports中的bean A
- @Import中的value指定的类如果实现了DeferedImportSelector 则交给deferedImportSelectorHandler进行处理 B(放到一个list中,parse解析完成后再调用)
- @Import中的value指定的类如果实现了ImportBeanDefinitionRegistrar 则加入到configClass的ImportBeanDefinitionRegistrar集合中,后续使用。
- 如果123都不满足则作为配置类进行解析, 也就是调用processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
对于1中解析出来的bean再进行判断 迭代走123的流程
-
@ImportResource
-
@Bean