【框架专题】——管理型容器——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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值