spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)

目录

一、@Import 注解分析

二、@ImportResource注解分析

 三、@bean注解收集分析


spring 源码ConfigurationClassParser类解析收集 Import、ImportResource 、bean等相关注解继续分享,承接上篇文章:

一、@Import 注解分析

此注解非常重要,涉及的功能点也比较多,重要的四点如下:

 @Import的作用是创建Spring bean,具体有四种用法

1) 导入普通类,即将普通类变为bean

2) 导入@Configuration,即将该注解生效,具体来说就是:将其注解的类成为bean,该类中的@Bean注解的方法也变为bean。注:在应用启动类上使用@ComponentScan也能让@Configuration生效

3) 导入ImportSelector的实现类。ImportSelector接口中定义了方法selectImports,它返回字符串数组,里面是类的全路径。使用@Import导入ImportSelector的实现类,就是将selectImports方法返回的类注册为bean

4)导入ImportBeanDefinitionRegistrar的实现类。ImportBeanDefinitionRegistrar接口中定义了方法registerBeanDefinitions,它的功能就是通过BeanDefinitionRegistry实例注册bean。

这四点功能下面会通过源码结合业务代码详细验证,源码入口如下:

       //处理@Import注解 getImports(sourceClass) 获取类上面的@Import注解并封装成SourceClass
		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

点击进入

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection importCandidates, Predicate exclusionFilter,
			boolean checkForCircularImports) {

		//如果没有@Import注解直接返回,不处理
		if (importCandidates.isEmpty()) {
			return;
		}

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				//循环类上面的每一个@Import
				for (SourceClass candidate : importCandidates) {
					//如果Import进来的是一个ImportSelector类型
					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 selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						//如果是一个DeferredImportSelector类型
						if (selector instanceof DeferredImportSelector) {
							//比较复杂,springboot中自动配置用到了
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							//在这里调用selectImports方法,返回所有的需要import到spring容器的beanName,这里直接调用了。
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							//递归处理,有可能import进来的类又有@Import注解
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}
					//如果Import进来的是一个ImportBeanDefinitionRegistrar类型,而此接口的实现类此代码块没有调用,而是在对象实例化完成之后才调用,这就是和上面接口的差异
					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 =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						//加入到importBeanDefinitionRegistrars容器中,这里还没有调用registerBeanDefinitions
						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), 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();
			}
		}
	}

测试数据

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第1张图片 进入

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第2张图片

  1、测试的伪代码如下

 

import com.enjoy.jack.aware.AwareBean;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;

 
@Component
//Import虽然是实例化一个类,Import进来的类可以实现一些接口
@Import({DeferredImportSelectorDemo.class,LisonSelectImport.class,JamesImportBeanDefinitionRegistrar.class, AwareBean.class})
public class ImportBean {
  //省略......
}

 DeferredImportSelectorDemo 类

import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.type.AnnotationMetadata;

import java.util.ArrayList;
import java.util.List;

 
public class DeferredImportSelectorDemo implements DeferredImportSelector {
    
    //这个接口是下面的   String[] strings = selector.selectImports(metadata); 来调用
   //即如果没有下面的调用,源码是不会调用这里的,因为你实现的是 DeferredImportSelector 接口
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("=====DeferredImportSelectorDemo.selectImports");
       // return new String[]{SelectImportBean.class.getName()};
        return new String[]{SelectImportBean.class.getName()};
    }

    /**
     * 要返回一个实现了Group接口的类,这个内部类没有的话,下面几个接口是不会调用的
       可以结合源码测试一下
    */
    @Override
    public Class getImportGroup() {
        return DeferredImportSelectorGroupDemo.class;
    }

    private static class DeferredImportSelectorGroupDemo implements Group {

        List list = new ArrayList<>();
        /**
            收集需要实例化的类
        */
        @Override
        public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
            System.out.println("=====DeferredImportSelectorGroupDemo.process");
            String[] strings = selector.selectImports(metadata);
            for (String string : strings) {
                list.add(new Entry(metadata,string));
            }
        }

        @Override
        public Iterable selectImports() {
            System.out.println("=====DeferredImportSelectorGroupDemo.selectImports");
            return list;
        }
    }
}

继续继承

public interface DeferredImportSelector extends ImportSelector {

 LisonSelectImport 类

import com.enjoy.jack.bean.Nandao;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @Author Nandao
 * LisonSelectImport 此类不会被实例化到spring容器中;如果不实现ImportSelector接口,会实例化到容器中
 */
public class LisonSelectImport implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
      //  MergedAnnotations annotations = importingClassMetadata.getAnnotations();
      //  MergedAnnotation eas = annotations.get(EnableAspectJAutoProxy.class);

    //    Object proxyTargetClass = eas.getValue("proxyTargetClass").get();
        //类的完整限定名,
        System.out.println("nandao is OK");
        return new String[]{Nandao.class.getName()};
    }
}

比如测试:

   @Test
    public void test4() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanBean.class);
        LisonSelectImport bean = applicationContext.getBean(LisonSelectImport.class);
        System.out.println(bean);
    }

 测试结果

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第3张图片

 JamesImportBeanDefinitionRegistrar 类

import com.enjoy.jack.bean.BeanDefinitionBean;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

 
public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //自己创建beanDefinition对象,然后注册到BeanDefinitionRegistry中
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(BeanDefinitionBean.class);
        MutablePropertyValues propertyValues = genericBeanDefinition.getPropertyValues();
        propertyValues.add("name","Jack");
        registry.registerBeanDefinition("beanDefinitionBean",genericBeanDefinition);
    }
}

AwareBean 类

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

 
public class AwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, EnvironmentAware, ImportAware, InitializingBean {
    @Override
    public void setBeanName(String name) {
        System.out.println(name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println(beanFactory);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext);
    }

    @Override
    public void setEnvironment(Environment environment) {
        System.out.println(environment);
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        //这个方法就是要拿到注解的值
        MergedAnnotations annotations = importMetadata.getAnnotations();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("========afterPropertiesSet");
    }
}

2、源码开始遍历

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第4张图片

点击  ParserStrategyUtils.instantiateClass 方法,进入反射生成对象

static  T instantiateClass(Class clazz, Class 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);
		ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader);
		return instance;
	}

返回后生成一个空对象

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第5张图片 进入这里  this.deferredImportSelectorHandler.handle(),点击进入

public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
			if (this.deferredImportSelectors == null) {
				//创建DeferredImportSelectorGroup接口的处理类
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				handler.register(holder);//点击进入
				handler.processGroupImports();//点击进入
			}
			else {
				this.deferredImportSelectors.add(holder);
			}
		}

3、点击 handler.register(holder);来到

public void register(DeferredImportSelectorHolder deferredImport) {
			//调用getImportGroup方法,返回实现了Group接口的类
			Class group = deferredImport.getImportSelector().getImportGroup();
			//建立实现了Group接口类和DeferredImportSelectorGrouping的映射关系
			DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
					(group != null ? group : deferredImport),
					key -> new DeferredImportSelectorGrouping(createGroup(group)));
			grouping.add(deferredImport);
			this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getConfigurationClass());
		}

点击deferredImport.getImportSelector().getImportGroup();进入业务方法

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第6张图片

 点击  handler.processGroupImports();

	public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				Predicate exclusionFilter = grouping.getCandidateFilter();
				//这里调用了 group.selectImports()
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
						//又递归处理每一个返回的Entry
						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);
					}
				});
			}
		}

点击grouping.getImports()

	public Iterable getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                //进入业务方法
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			//在这里调用了实现了Group接口的selectImports方法,进入业务方法
			return this.group.selectImports();
		}

 点击this.group.process方法

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第7张图片

 点击this.group.selectImports() 进入业务方法

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第8张图片

 如果不是第一次就会放入

this.deferredImportSelectors.add(holder);

下游业务会执行

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第9张图片

点击进入

	public void process() {
			List 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<>();
			}
		}

  4、遍历到第二个对象

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第10张图片

 往下走到这里进入业务方法  selectImports

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第11张图片

 业务方法

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第12张图片

 5、 第三次遍历

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第13张图片

6、第四次遍历

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第14张图片

点击 processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);

protected void processConfigurationClass(ConfigurationClass configClass, Predicate filter) throws IOException {
		//对@Condition注解的支持,过滤掉不需要实例化的类
		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);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		//这个对象理解为跟类或者接口对应,然后把metadata对象包装进去了
		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			//核心代码,认真读
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}

点击asSourceClass(configClass, filter);

	private SourceClass asSourceClass(ConfigurationClass configurationClass, Predicate filter) throws IOException {
		AnnotationMetadata metadata = configurationClass.getMetadata();
		if (metadata instanceof StandardAnnotationMetadata) {
			return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass(), filter);
		}
		return asSourceClass(metadata.getClassName(), filter);
	}

 点击 asSourceClass(metadata.getClassName(), filter);

SourceClass asSourceClass(@Nullable String className, Predicate filter) throws IOException {
		if (className == null || filter.test(className)) {
			return this.objectSourceClass;
		}
		if (className.startsWith("java")) {
			// Never use ASM for core java types
			try {
				return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new NestedIOException("Failed to load class [" + className + "]", ex);
			}
		}
		return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
	}

返回点击  sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);

 进入循环递归调用环节

最后收集的对象在这里调用

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第15张图片

 进入

spring 源码ConfigurationClassParser类解析收集Import、ImportResource 、bean等相关注解(二)_第16张图片

即里面实现的接口最终都会系统调用。 

总之,分析此注解得出结论:

1)声明一个bean

2)导入@Configuration注解的配置类

3)导入ImportSelector的实现类

4)导入ImportBeanDefinitionRegistrar的实现类

即@Import用来导入@Configuration注解的配置类、声明@Bean注解的bean方法、导入ImportSelector的实现类或导入ImportBeanDefinitionRegistrar的实现类。

二、@ImportResource注解分析

源码入口

//处理@ImportResource注解 ,加载xml配置文件
		// Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				//建立xml文件和reader的映射关系
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

比如业务场景

@ImportResource("classpath:spring.xml")
public class ImportBean {
    //省略......
}

 此处源码仅仅是加载保存,下游业务解析时会用到。

 三、@bean注解收集分析

源码入口

		//处理@Bean注解,重点
		// Process individual @Bean methods
		//收集有@bean 注解的方法
		Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			//加入到ConfigurationClass中
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		//处理接口里面方法有@Bean注解的,逻辑差不多
		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

1、点击  retrieveBeanMethodMetadata(sourceClass);方法

private Set retrieveBeanMethodMetadata(SourceClass sourceClass) {
		AnnotationMetadata original = sourceClass.getMetadata();
		Set beanMethods = original.getAnnotatedMethods(Bean.class.getName());
		if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
			// Try reading the class file via ASM for deterministic declaration order...
			// Unfortunately, the JVM's standard reflection returns methods in arbitrary
			// order, even between different runs of the same application on the same JVM.
			try {
				AnnotationMetadata asm =
						this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
				Set asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
				if (asmMethods.size() >= beanMethods.size()) {
					Set selectedMethods = new LinkedHashSet<>(asmMethods.size());
					for (MethodMetadata asmMethod : asmMethods) {
						for (MethodMetadata beanMethod : beanMethods) {
							if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
								selectedMethods.add(beanMethod);
								break;
							}
						}
					}
					if (selectedMethods.size() == beanMethods.size()) {
						// All reflection-detected methods found in ASM method set -> proceed
						beanMethods = selectedMethods;
					}
				}
			}
			catch (IOException ex) {
				logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
				// No worries, let's continue with the reflection metadata we started with...
			}
		}
		return beanMethods;
	}

2、点击  processInterfaces(configClass, sourceClass);

private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
		for (SourceClass ifc : sourceClass.getInterfaces()) {
            //找方法上有@Bean的注解
			Set beanMethods = retrieveBeanMethodMetadata(ifc);
			for (MethodMetadata methodMetadata : beanMethods) {
				if (!methodMetadata.isAbstract()) {
					// A default method or other concrete method on a Java 8+ interface...
					configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
				}
			}
			processInterfaces(configClass, ifc);//循环递归查询
		}
	}

 收集完之后 作为参数封装到 ConfigurationClass  对象里,下游业务会详细解析!

到此、六种注解分享完毕,大家一定多多测试,深入理解,定会早日掌握!

你可能感兴趣的:(spring源码学习,spring)