我是靠谱客的博主 甜蜜耳机,最近开发中收集的这篇文章主要介绍【框架专题】——管理型容器——SpringBoot自动配置原理与SPI编程风格,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

spring.factories——实现类设计思想

面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则

如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制

spring.factories就是一套SPI的服务发现编程方式,让很多接口组合在这里统一表现以及明确实现类分布在何处,而不需要在代码里一个个去找

spring.factories——文件扫描

SpringBoot在启动的时候,会扫描在每个maven包下面的/META-INF/spring.factories这个文件,在这个文件中找到所有必要的类并实例化他们用于完成SpringBoot自动配置的功能;

SpringBootApplication 注解包含了@EnableAutoConfiguration


@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
@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 {
}

@EnableAutoConfiguration注册了AutoConfigurationImportSelector作为选择器

所以ioc在初始化的时候就会用这个自动配置类选择器运行自动配置相关代码,这些都ioc直接完成的,所以我接下来直接看AutoConfigurationImportSelector

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

AutoConfigurationImportSelector 中的AutoConfigurationGroup

返回一个class类型,ioc会直接创建这个类型的实例

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	public Class<? extends Group> getImportGroup() {
		return AutoConfigurationGroup.class;
	}
}

题外:ConfigurationClassParser调用process

ConfigurationClassParser专用于ioc中解析配置类,该类会解析@Import标签实例化里面的类,并调用group的process方法

class ConfigurationClassParser {
  private static class DeferredImportSelectorGrouping {
     public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			return this.group.selectImports();
	}
  }
}

AutoConfigurationGroup的process实现

private static class AutoConfigurationGroup
			implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
	public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	        /*
	          获取自动配置数组
	         */
			AutoConfigurationEntry autoConfigurationEntry = 
			((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(annotationMetadata);
		}
}

AutoConfigurationImportSelector获取配置信息

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		
		/*
		   找到所有类的string描述
		 */
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		/*
		   回调事件
		 */
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
	/*
	    回调onAutoConfigurationImportEvent事件
	 */
	private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}
	/* 
	  调用SpringFactoriesLoader开始读取
	 */
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		return configurations;
	}
}

SpringFactoriesLoader 读取配置文件


public final class SpringFactoriesLoader {
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}
		private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}
		/*
		  FACTORIES_RESOURCE_LOCATION就是META-INF/spring.factories
		 */
		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()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}

}

spring.factories——举例应用

以RedisAutoConfiguration为例,看看他是如何实现自动配置的;

RedisAutoConfiguration在META-INF/spring.factories中服务发现后,会被实例化成为ioc容器内的bean,此时我们只需要看待普通bean去看待这个RedisAutoConfiguration 即可;
我们发现
(1)@EnableConfigurationProperties引入了RedisProperties的配置数据信息
(2)@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })引入了redis的两个配置类信息

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
   @Bean
   @ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
	@Bean
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
}

@EnableConfigurationProperties

直接用选择器引入了@EnableConfigurationPropertiesRegistrar**

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
}
class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
   /*
     利用注解注册这些properties,比如上面的RedisProperties对象就是来在于springboot的集中化配置
    */
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		registerInfrastructureBeans(registry);
		ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
		getTypes(metadata).forEach(beanRegistrar::register);
	}
}

LettuceConnectionConfiguration

利用构造器注入了ioc的RedisProperties,传给父类RedisConnectionConfiguration 去保存着

class LettuceConnectionConfiguration extends RedisConnectionConfiguration {

	LettuceConnectionConfiguration(RedisProperties properties,
			ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
			ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
		super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
	}
}

spring.factories——文件内容

spring.factories就是一套SPI的服务发现编程方式,让很多接口组合在这里统一表现以及明确实现类分布在何处,而不需要在代码里一个个去找

EnableAutoConfiguration

完成自动配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
	org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,
	org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,
	org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration

AutoConfigurationImportFilter

完成过滤注入注解的实现

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=
	org.springframework.boot.autoconfigure.condition.OnBeanCondition,
	org.springframework.boot.autoconfigure.condition.OnClassCondition,
	org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

其他

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=
	org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
	
org.springframework.context.ApplicationListener=
	org.springframework.boot.autoconfigure.BackgroundPreinitializer
	
org.springframework.context.ApplicationContextInitializer=
	org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
	org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListene

org.springframework.boot.diagnostics.FailureAnalyzer=
	org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,
	org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,
	org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,
	org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,
	org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,
	org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=
	org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,
	org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,
	org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,
	org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,
	org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

最后

以上就是甜蜜耳机为你收集整理的【框架专题】——管理型容器——SpringBoot自动配置原理与SPI编程风格的全部内容,希望文章能够帮你解决【框架专题】——管理型容器——SpringBoot自动配置原理与SPI编程风格所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部