1、概述
Spring boot 在进行SpringApplication对象实例化会加载 META/spring.factories文件,将该配置文件中的配置载入到Spring容器。
META/spring.factories 文件位置
2、SpringApplication 源码分析
/**
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
/**
* 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
*/
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null)
return result;
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(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) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
3、条件注解
@ConditionalOnBean : 当容器里有指定的bean的条件下
@ConditionalOnClass :当类路径下有指定的类的条件下
@ConditionalOnExpression : 基于SpEL表达式作为判断条件
@ConditionalOnJava : 基于jvm版本作为判断条件
@ConditionalOnJndi : 在 JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean : 当容器里没有指定的bean的情况下
@ConditionalOnMissingClass : 当类路径下没有指定的类的条件下
@ConditionalOnNotWebApplication : 当前项目不是web项目的条件下
@ConditionalOnProperty : 指定的属性是否有指定的值
@ConditionalOnResource : 类路径是否有指定的值
@ConditionalOnSingleCandidate : 当指定bean 在容器中只有一个,或者虽然有多个但是指定首选的bean
@ConditionalOnWebApplication : 当前项目时web项目的条件下