springboot自动装配源码分析

目录

前言

一、自动装配类的加载过程

二、自动加载属性

总结


前言

       springboot提供了自动装配的功能,简化了配置。自动装配应该包含配置类的导入和属性的赋值两个过程,本文基于源码分析这两个过程。


一、自动装配类的加载过程

       首先从SpringBootApplocation注解进行分析,包含了EnableAutoConfiguration注解,在该注解中引入了AutoConfigurationImportSelector类,该类实现了DeferredImportSelector接口,主要逻辑就位于这个类中。

@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 {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered 

           首先在spring加载bean定义的过程中,会调用到deferedImport的group的process方法,selectImports方法,下面依次进行分析。

  this.deferredImportSelectorHandler.process(); 
  grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
			try {
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
								Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
				exclusionFilter, false);

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

          在process方法中,比较重要的方法是getAutoConfigurationMetadata和getAutoConfigurationEntry方法,分别实现了配置元数据和配置类的加载。

	public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
		Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
					() -> String.format("Only %s implementations are supported, got %s",
							AutoConfigurationImportSelector.class.getSimpleName(),
							deferredImportSelector.getClass().getName()));
			//加载自动配置的类
		AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
		this.autoConfigurationEntries.add(autoConfigurationEntry);
		for (String importClassName : autoConfigurationEntry.getConfigurations()) {
			this.entries.putIfAbsent(importClassName, annotationMetadata);
		}
	}

           getAutoConfigurationMetadata方法,主要就是从META-INF/spring-autoconfigure-metadata.properties文件中读取配置元数据。

		//获取META-INF/spring-autoconfigure-metadata.properties中的数据
		private AutoConfigurationMetadata getAutoConfigurationMetadata() {
			if (this.autoConfigurationMetadata == null) {
				this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
			}
			return this.autoConfigurationMetadata;
		}

       getAutoConfigurationEntry方法首先从spring.factories中读取需要装配的全类名,然后使用元数据进行过滤,将过滤后的类构建AutoConfigurationEntry。

	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//读取所有的spring.factories中的全类名
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		//使用spring-autoconfigure-metadata.properties文件中的数据过滤
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

            在selectImports方法中主要是将过滤之后的类返回,并加载到容器中。

		public Iterable<Entry> selectImports() {
			if (this.autoConfigurationEntries.isEmpty()) {
				return Collections.emptyList();
			}
			Set<String> allExclusions = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
			Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
					.collect(Collectors.toCollection(LinkedHashSet::new));
			processedConfigurations.removeAll(allExclusions);
			//返回文件中加载的类
			return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
					.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
					.collect(Collectors.toList());
		}

二、自动加载属性

       本文以RabbitAutoConfiguration为例,在rabbitConnectionFactory的创建过程中依赖RabbitProperties,同时,RabbitProperties类中的属性也是配置文件中需要配置的属性,可以自动装配到rabbitConnectionFactory中,下面主要分析配置的属性是如何与RabbitProperties关联的。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingBean(ConnectionFactory.class)
	protected static class RabbitConnectionFactoryCreator {

		@Bean
		public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties properties,
				ObjectProvider<ConnectionNameStrategy> connectionNameStrategy) throws Exception {
			PropertyMapper map = PropertyMapper.get();
			CachingConnectionFactory factory = new CachingConnectionFactory(
					getRabbitConnectionFactoryBean(properties).getObject());
			map.from(properties::determineAddresses).to(factory::setAddresses);
			map.from(properties::isPublisherReturns).to(factory::setPublisherReturns);
			map.from(properties::getPublisherConfirmType).whenNonNull().to(factory::setPublisherConfirmType);
			RabbitProperties.Cache.Channel channel = properties.getCache().getChannel();
			map.from(channel::getSize).whenNonNull().to(factory::setChannelCacheSize);
			map.from(channel::getCheckoutTimeout).whenNonNull().as(Duration::toMillis)
					.to(factory::setChannelCheckoutTimeout);
			RabbitProperties.Cache.Connection connection = properties.getCache().getConnection();
			map.from(connection::getMode).whenNonNull().to(factory::setCacheMode);
			map.from(connection::getSize).whenNonNull().to(factory::setConnectionCacheSize);
			map.from(connectionNameStrategy::getIfUnique).whenNonNull().to(factory::setConnectionNameStrategy);
			return factory;
		}

}
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitProperties {

	/**
	 * RabbitMQ host.
	 */
	private String host = "localhost";

	/**
	 * RabbitMQ port.
	 */
	private int port = 5672;

	/**
	 * Login user to authenticate to the broker.
	 */
	private String username = "guest";

}

          RabbitAutoConfiguration上有一个注解EnableConfigurationProperties,在该注解中引入了EnableConfigurationPropertiesRegistrar类。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {

	/**
	 * The bean name of the configuration properties validator.
	 * @since 2.2.0
	 */
	String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";

	/**
	 * Convenient way to quickly register
	 * {@link ConfigurationProperties @ConfigurationProperties} annotated beans with
	 * Spring. Standard Spring Beans will also be scanned regardless of this value.
	 * @return {@code @ConfigurationProperties} annotated beans to register
	 */
	Class<?>[] value() default {};

}

         EnableConfigurationPropertiesRegistrar将ConfigurationPropertiesBindingPostProcessor和@EnableConfigurationProperties注解中的类加载到容器中。

class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		//注册ConfigurationPropertiesBindingPostProcessor到容器中
		registerInfrastructureBeans(registry);
		ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
		//获取注解@EnableConfigurationProperties指定的被@ConfigurationProperties注解标注的bean实例对象
		//forEach循环调用注册器方法将@ConfigurationProperties标注的bean注册到IOC容器之中
		getTypes(metadata).forEach(beanRegistrar::register);
	}
}

        ConfigurationPropertiesBindingPostProcessor实现了BeanPostProcessor接口,在postProcessBeforeInitialization方法中,会给含有ConfigurationProperties注解的类中的属性赋值,在环境中查找对应属性,赋值时是在bean创建的过程中,此时相关属性已经加载到容器中。将环境中的属性加载到RabbitProperties对象中,可以在创建CachingConnectionFactory时将属性装配。

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		//绑定有ConfigurationProperties注解的类的属性,给属性赋值
		bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
		return bean;
	}

       在一个bean中有大量的属性需要注入可以使用configurationProperties,注入个别属性还是使用value注解.

总结

        本文对springboot的自动装配原理进行了分析,EnableAutoConfiguration注解引入了AutoConfigurationImportSelector类,在该类中,会加载spring.factory文件中的类,并使用pring-autoconfigure-metadata.properties文件中的元数据进行过滤。EnableConfigurationProperties注解引入了ConfigurationPropertiesRegistrar,在其中注入了EnableConfigurationProperties注解中的类和ConfigurationPropertiesBindingPostProcessor,该类会在postProcessBeforeInitialization方法中对带有ConfigurationProperties注解的类进行属性赋值,在自动装配类中将相关属性配置进去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值