@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage//Indicates that the package containing the annotated class should be registered with@Import(AutoConfigurationImportSelector.class)//自动配置导入选择器public @interfaceEnableAutoConfiguration{
String ENABLED_OVERRIDE_PROPERTY ="spring.boot.enableautoconfiguration";/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[]exclude()default{};/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[]excludeName()default{};}
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/protected List<String>getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes){// getSpringFactoriesLoaderFactoryClass()方法的返回值org.springframework.boot.autoconfigure.EnableAutoConfiguration// 返回的就是spring.factories中org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置值
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories. If you "+"are using a custom packaging, make sure that file is correct.");return configurations;}/**
* Return the class used by {@link SpringFactoriesLoader} to load configuration
* candidates.
* @return the factory class
*/protected Class<?>getSpringFactoriesLoaderFactoryClass(){return EnableAutoConfiguration.class;}
/**
* Load the fully qualified class names of factory implementations of the
* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
* class loader.
* @param factoryClass the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @see #loadFactories
* @throws IllegalArgumentException if an error occurs while loading factory names
*/publicstatic List<String>loadFactoryNames(Class<?> factoryClass,@Nullable ClassLoader classLoader){
String factoryClassName = factoryClass.getName();returnloadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}privatestatic Map<String, List<String>>loadSpringFactories(@Nullable ClassLoader classLoader){
MultiValueMap<String, String> result = cache.get(classLoader);if(result != null){return result;}try{// FACTORIES_RESOURCE_LOCATION 的值就是META-INF/spring.factories//The location to look for factories, Can be present in multiple JAR files//public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
Enumeration<URL> urls =(classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION):
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result =newLinkedMultiValueMap<>();while(urls.hasMoreElements()){
URL url = urls.nextElement();
UrlResource resource =newUrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);for(Map.Entry<?,?> entry : properties.entrySet()){
List<String> factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);}}
cache.put(classLoader, result);return result;}catch(IOException ex){thrownewIllegalArgumentException("Unable to load factories from location ["+
FACTORIES_RESOURCE_LOCATION +"]", ex);}}