SpringBoot源码---SpringBoot中的SPI实现方式

    上一篇文章中提到SpringBoot中实现自动配置时,用到了SPI机制。不知道会不会有有心人去看看我推荐的那篇博文。本篇文章将从代码的层次深入解读Springboot的SPI机制。

   首先,是一个很重要的注解@EnableAutoConfiguration,它的源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	Class[] exclude() default {};

	String[] excludeName() default {};

}

  @EnableAutoConfiguration注解就是SpringBoot实现自动配置的关键了。因为注解在底层会被翻译为接口,继承注解本质上等同于继承接口,所以@SpringBootApplication注解继承了@EnableAutoConfiguration注解后,就有了@EnableAutoConfiguration注解的能力。

      我们再来说说@Import注解,上篇文章提到了它的作用机制。这篇文章中又要用到它的特性了。我们来看看EnableAutoConfigurationImportSelector类的部分源码:

public class EnableAutoConfigurationImportSelector implements DeferredImportSelector,
		BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware {

	private ConfigurableListableBeanFactory beanFactory;

	private Environment environment;

	private ClassLoader beanClassLoader;

	private ResourceLoader resourceLoader;

	@Override
	public String[] selectImports(AnnotationMetadata metadata) {
		try {
			AnnotationAttributes attributes = getAttributes(metadata);
			List configurations = getCandidateConfigurations(metadata,
					attributes);
			configurations = removeDuplicates(configurations);
			Set exclusions = getExclusions(metadata, attributes);
			configurations.removeAll(exclusions);
			configurations = sort(configurations);
			recordWithConditionEvaluationReport(configurations, exclusions);
			return configurations.toArray(new String[configurations.size()]);
		}
		catch (IOException ex) {
			throw new IllegalStateException(ex);
		}
	}

}

  这是精简了很大篇幅代码后的部分源码(其他部分多数都是被此方法调用的方法)。我们不知道它是干嘛的,但是可以知道是谁调用了它,我们来看看调用关系:

SpringBoot源码---SpringBoot中的SPI实现方式_第1张图片

已经很说明问题了吧?在Spring容器启动过程中,会通过invokeBeanFactoryPostProcessors()方法执行很多BeanFactoryPostProcessors()方法来完成BeanFactory的初始化。在这个过程中,EnableAutoConfigurationImportSelector类的selectImports()方法也被调用了。

接下来,我们来看看selectImports()方法都做了些什么?EnableAutoConfigurationImportSelector类导入了一个这样的包:

import org.springframework.core.io.support.SpringFactoriesLoader;

我们看看它的源码(精简):

public abstract class SpringFactoriesLoader {

	private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);

	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";


	public static  List loadFactories(Class factoryClass, ClassLoader classLoader) {
	
	}

	public static List loadFactoryNames(Class factoryClass, ClassLoader classLoader) {
		
	}

}

 这个类我们有利于我们继续往下找线索的代码是这一行:

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

有了这一行代码,我们大致就可以猜出来这个SpringFactoriesLoader类大概是干嘛的了吧?它的两个核心方法一个是用来寻找spring.factories文件中的Factory名称的,一个是用来寻找类的。我们再来看看EnableAutoConfigurationImportSelector类中是怎样使用SpringFactoriesLoader类的,以一段代码如下:

protected List getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
   return SpringFactoriesLoader.loadFactoryNames(
		getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
}

我们现在再来看看selectImports()方法:

public String[] selectImports(AnnotationMetadata metadata) {
	try {
	    AnnotationAttributes attributes = getAttributes(metadata);
            //从spring.factories文件中找出所有配置好的factory的名称
        List configurations = getCandidateConfigurations(metadata,
					attributes);
           //去重
	    configurations = removeDuplicates(configurations);
           //分析所有需要排除掉的factory类(EnableAutoConfiguration注解中配置的)
            Set exclusions = getExclusions(metadata, attributes);
           //移除所有需要过滤放入factory类
	    configurations.removeAll(exclusions);
           //排序
	    configurations = sort(configurations);
           //记录
	    recordWithConditionEvaluationReport(configurations, exclusions);
           //数组形式返回
	    return configurations.toArray(new String[configurations.size()]);
	}
	catch (IOException ex) {
		throw new IllegalStateException(ex);
	}
}

 

你可能感兴趣的:(springboot源码)