Springboot 源码之 如何完成自动装配

187 阅读2分钟

从@SpringBootApplication 开始

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
      .......
}

@SpringBootApplication 上的 @EnableAutoConfiguration

从这个注解字面上的意思就是能够自动化配置,springboot很多注解都是以enable开头的,他们的实现都差不多

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ......
}

@import 很重要,就是实现enable相关注解的关键 所以springboot实现自动化装配的第一步就是@import (需要了解 ConfigurationClassPostProcessor 这个类)

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector#selectImports 方法

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		//这个调用一层套一层,简单的说就是从spring.factories中获得
		//key 为 EnableAutoConfiguration这个注解的全类名,spring会调用
		//本方法,将返回去的类进行解析实例化并且注册到spring容器中
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
				autoConfigurationMetadata, annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

比如说EmbeddedWebServerFactoryCustomizerAutoConfiguration 这个类就会被解析出来

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
...........
}

可以看到上面有个很重要的注解 @EnableConfigurationProperties(ServerProperties.class)

@EnableConfigurationProperties(ServerProperties.class) 这句代码做了什么

//又是import 可见 这个注解多么重要
@Import(EnableConfigurationPropertiesImportSelector.class)
public @interface EnableConfigurationProperties {
    ....
}

EnableConfigurationPropertiesImportSelector 这个类做了什么

	private static final String[] IMPORTS = {
			ConfigurationPropertiesBeanRegistrar.class.getName(),
			ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName() };

	@Override
	public String[] selectImports(AnnotationMetadata metadata) {
	//返回 ConfigurationPropertiesBeanRegistrar 和 //ConfigurationPropertiesBindingPostProcessorRegistrar 让spring解析注册到spring容器中
		return IMPORTS;
	}

ConfigurationPropertiesBeanRegistrar

	public static class ConfigurationPropertiesBeanRegistrar
			implements ImportBeanDefinitionRegistrar {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
	//在解析 ConfigurationPropertiesBeanRegistrar 的时候会调用这个方法
	//这个方法干嘛的?
	//会拿到@EnableConfigurationProperties(ServerProperties.class) 注解上的的value,比如这个 ServerProperties 然后注册到 spring容器中,所以ServerProperties就被spring管理起来了
			getTypes(metadata).forEach((type) -> register(registry,
					(ConfigurableListableBeanFactory) registry, type));
		}
		}

ServerProperties 配置类

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

	/**
	 * Network address to which the server should bind.
	 */
	private InetAddress address;
	.......
	}

这个类很熟悉,就是我们在application.yml 中使用到的,server.prot等等,到了这一步,spring已经把ServerProperties注册成beandefinition,但是什么时候把这个配置类的属性从application.yml中获取到。 还有个类没有说到 ConfigurationPropertiesBindingPostProcessorRegistrar (上文有)

	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
			BeanDefinitionRegistry registry) {
	//判断spring中有没有 
	### ConfigurationPropertiesBindingPostProcessor这个类 
	//如果没有就往 spring注册
	//(这个方法会被反复执行,但是只会注册一次,不知道为啥spring在这边没有优化)
		if (!registry.containsBeanDefinition(
				ConfigurationPropertiesBindingPostProcessor.BEAN_NAME)) {
			registerConfigurationPropertiesBindingPostProcessor(registry);
			registerConfigurationBeanFactoryMetadata(registry);
		}
	}

ConfigurationPropertiesBindingPostProcessor 有什么作用

这就涉及到spring bena的生成 这个类实现了BeanPostProcessor 是spring的一种后置处理器。

//在 bean 实例化之后,初始化之前执行
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		ConfigurationProperties annotation = getAnnotation(bean, beanName,
				ConfigurationProperties.class);
		if (annotation != null) {
		// 执行绑定逻辑,将配置跟bean中的属性绑定,完成自动化装配
			bind(bean, beanName, annotation);
		}
		return bean;
	}

一层套一层............