05-Eureka源码解析SpringBoot中的自动装载
目录
1、SpringBoot中的自动装载
1.1、ImportSelector
1.2、springBoot自动装载
1、SpringBoot中的自动装载
1.1、ImportSelector
ImportSelector接口是Spring导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功能性注解)中起到了决定性的作用。当在@Configuration标注的Class上使用@Import引入了一个ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。
DeferredImportSelector接口继承ImportSelector,他和ImportSelector的区别在于装载bean的时机
上,DeferredImportSelector需要等所有的@Configuration都执行完毕后才会进行装载
接下来我们写一个小例子,看下ImportSelector的用法
1)定义Bean对象
public class User {
private String username;
private Integer age;
//省略..
}
2)定义配置类Configuration
//定义一个configuration ,注意这里并没有使用spring注解,spring扫描的时候并不会装载该类
public class UserConfiguration {
@Bean
public User getUser() {
return new User("张三",18);
}
}
3 ) 定义ImportSelector
public class UserImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//获取配置类名称
return new String[]{UserConfiguration.class.getName()};
}
}

4) 定义EnableXXX注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import(UserImportSelector.class)
public @interface EnableUserBean {
}
5 ) 测试
/**
* 通过在类上声明@EnableUserBean,会自动的加载所有对象
*/
@EnableUserBean
public class TestApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new
AnnotationConfigApplicationContext(TestApplication.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
}
}
由此可见,HelloWorldConfiguration对象并没有使用Spring的对象对象创建注解声明(@Controller,@Service,@Repostiroty),而是使用编程的方式动态的载入bean。
这个接口在哪里调用呢?我们可以来看一下ConfigurationClassParser这个类的processImports方法
private void processImports(ConfigurationClass configClass, SourceClass
currentSourceClass,Collection<SourceClass> importCandidates, booleancheckForCircularImports) {
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);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader,
this.registry);
if (this.deferredImportSelectors != null && selector
instanceof DeferredImportSelector) { //如果为延迟导入处理
则加入集合当中
this.deferredImportSelectors.add(
new
DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else { //根据ImportSelector方法
的返回值来进行递归操作
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);
configClass.addImportBeanDefinitionRegistrar(registrar,
currentSourceClass.getMetadata());
}
else { // 如果当前的类既不是
ImportSelector也不是ImportBeanDefinitionRegistar就进行@Configuration的解析处理
// 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));
}
在这里我们可以看到ImportSelector接口的返回值会递归进行解析,把解析到的类全名按照@Configuration进行处理
1.2、springBoot自动装载
SpringBoot开箱即用的特点,很大程度上归功于ImportSelector。接下来我们看下springBoot是如何在spring的基础上做扩展的。在SpringBoot中最重要的一个注解SpringBootApplication
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
//...
}
在SpringBootApplication注解中声明了一个 @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 {};
}
在EnableAutoConfiguration中通过Import引入了SpringBoot定义的AutoConfigurationImportSelector
这个类内容比较多,我们只需看下最主要的逻辑代码即可
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware, Ordered { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); //主要逻辑在getAutoConfigurationEntry这个方法 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry( AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); //通过getCandidateConfigurations方法获取所有需要加载的bean List<String> configurations =getCandidateConfigurations(annotationMetadata, attributes); //去重处理 configurations = removeDuplicates(configurations); //获取不需要加载的bean,这里我们可以通过spring.autoconfigure.exclude人为配置 Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); //发送事件,通知所有的AutoConfigurationImportListener进行监听从上面的逻辑可以看出,最终获取bean的渠道在SpringFactoriesLoader.loadFactoryNames fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } //这里是获取bean渠道的地方,重点看SpringFactoriesLoader#loadFactoryNames protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //这里的getSpringFactoriesLoaderFactoryClass()最终返回 EnableAutoConfiguration.class List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in METAINF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; } }
从上面的逻辑可以看出,最终获取bean的渠道在SpringFactoriesLoader.loadFactoryNames
public final class SpringFactoriesLoader { public static final String FACTORIES_RESOURCE_LOCATION = "METAINF/spring.factories"; private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class); private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap(); public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); //通过factoryClassName获取相应的bean全称 //上面传入的factoryClass是EnableAutoConfiguration.class return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } 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 { //获取工程中所有META-INF/spring.factories文件,将其中的键值组合成Map 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(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } } } private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) { try { Class<?> instanceClass = ClassUtils.forName(instanceClassName, classLoader); if (!factoryClass.isAssignableFrom(instanceClass)) { throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]"); } else { return ReflectionUtils.accessibleConstructor(instanceClass, new Class[0]).newInstance(); } } catch (Throwable var4) { throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), var4); } } }UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } } } private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) { try { Class<?> instanceClass = ClassUtils.forName(instanceClassName, classLoader); if (!factoryClass.isAssignableFrom(instanceClass)) { throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]"); } else { return ReflectionUtils.accessibleConstructor(instanceClass, new Class[0]).newInstance(); } } catch (Throwable var4) { throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), var4); } } }
每个jar都可以定义自己的META-INF/spring.factories ,jar被加载的同时 spring.factories里面定义的
bean就可以自动被加载

浙公网安备 33010602011771号