@Import注解
Import注解可以导入一个class,该class可以为一个被Configuration注解的配置类,或者一个实现ImportSelector或者ImportBeanDefinitionRegustrar的类。关于import注解的解析在Spring的ConfigurationClassParser类中。
@Import
@Configuration} classes, {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar
1.configuration,导入该配置类的全部bean。
2.ImportSelector
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
//入参importingClassMetadata为使用最上层配置类对应的AnnotationMetadata,比如@Configuration @Enable*** AnnotationMetadata为@Configuration类而不是@Enable**注解对象的类。
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
应用上下文将会导入String数组中的类的全限定名指向的Bean
3.ImportBeanDefinitionRegistrar
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
//importingClassMetadata最开始的导入ImportBeanDefinitionRegistrar的配置类
//然后可以将BeanDefinition注册到入参registry中
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
@Import注解是在应用上下文refresh刷新时,调用BeanFactoryPostProcessor处理器时,调用spring自带的ConfigurationClassPostProcessor时解析的,具体解析过程在ConfigurationClassParser中。
@Enablexxx就是依赖@import注解和@Conditional注解实现的。
ConfigurationClassParser的doProcessConfigurationClass方法中有processImports实现
processImports(configClass, sourceClass, getImports(sourceClass), true);
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
Set<SourceClass> visited = new LinkedHashSet<>();
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
*/
//这里就是一个递归,递归解析所有非jvm的注解,收集import注解
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();
if (!annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
首先递归获取入口配置类下相关联的所有使用使用@Import注解的类(或者注解),获取其Import的class转换成SourceClass对象并加入visited集合,SourseClass其实是对class对象的包装,
//简单包装一个被注解注释的类,而不用考虑他是如何被加载的
private class SourceClass implements Ordered {
private final Object source; // Class or MetadataReader
private final AnnotationMetadata metadata;
可以获取某个class的所有注解元数据AnnotationMetadata。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, 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)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
//实例化
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
//如果selector如果也继承了environmentAware resourceLoaderAware等接口的话,则调用这些接口
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//调用selector.selectImport 参数为当前sourceClass
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
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 =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
// 将ImportBeanDefinitionRegistrar实例添加到ConfigurationClass中去
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
// 如果不是importSelector或者实现类,则将其作为ConfigurationClass解析
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
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();
}
}
}
然后依次遍历这些SourceClass,判断是不是ImportBeanDefinitionRegistrar或者ImportSelector的实现,如果不是,则将其作为配置类处理。最后所有这些导入的都转换为ConfigurationClass对象被ConfigurationClassPostProcessor解析。
spring boot自动装配原理:
@SpringBootApplication注解标记一个应用为springboot应用,其由三个注解组成,分别为为@EnableAutoConfiguration、@ComponentScan和@Configuration。@ComponentScan注解可以将同一包中所有配置类的bean引入,而对于其他包,除非显示通过@ComponentScan配置,否则其配置类中的Bean无法引入到。不过通过@EnableAutoConfiguration注解,将这些配置类及其包的位置加入到classpath的META-INF/spring.factories中,再配合上@ConditionalClass注解,则可以只要再maven中引入,classpath中存在某类,即可注入这些类对应的Bean.@EnableAutoConfiguration作用只不过是收集注册特定场景相关bean。
一般另一种引入其他包配置类的方式为自定义@Enable***注解比如@EnableDiscoveryClient
@EnableAutoConfiguration原理:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
实际上就是import了一个ImportSelector,不过只有spring.boot.enableautoconfiguration为true的时候才启用自动装配。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param autoConfigurationMetadata the auto-configuration metadata
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
//判断spring.boot.enableautoconfiguration是否为true
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
//这里会排出@EnableAutoConfiguration中exclude()的那些类,默认一个也不exclude
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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;
}
在getCandidateConfigurations方法中,会调用getCandidateConfigurations方法。getCandidateConfigurations方法中通过调用SpringFactoriesLoader的loadFactoryNames方法,在classpath中搜索所有META-INF/spring.factories文件并将其中预先配置的所有类的全限定名取出,最后会将这些类注册为Bean。
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
spring boot的自动装配一般搭配@ConditionalClass或者@ConditionalOnMissingBean注解使用。
所以当spring boot引入一个maven依赖时,如果该依赖的jar包下面的META-INF/spring.factories配置了org.springframework.boot.autoconfigure.EnableAutoConfiguration,则这些类会自动生成bean加载到应用上下文中。
网友评论