文章目录
前言
阅读本文最好懂得spring源码,springmvc源码知识,以及零配置mvc+内嵌tomcat,servlet的spi机制
本文springboot源码版本说明:2.0.2.RELEASE
2.2.4.RELEASE的版本笔者也阅读过,相较于2.0.2来说更合理,更清晰,但是为了入门简单,还是选择早期版本
自动配置原理
@SpringBootApplication -->
@EnableAutoConfiguration -->
@Import({AutoConfigurationImportSelector.class}) -->
class AutoConfigurationImportSelector implements DeferredImportSelector{
//读过spring源码的都知道ImportSelector会把selectImports返回的这些类都放到spring容器中
//annotationMetadata是你带有@SpringBootApplication的类的注解描述
public String[] selectImports(AnnotationMetadata annotationMetadata) {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
//exclude,excludeName
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//从META-INF/spring.factories文件读取
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = this.removeDuplicates(configurations);
//看看你的@SpringBootApplication的类有没有exclusions
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//这里过滤掉一些
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
总结一下原理就是从spring.factories文件读取自动配置类放到spring容器中,下面我们以一个自动配置类的实际例子看看
DispatcherServletAutoConfiguration
该类可以从spring.factories文件找到,
DispatcherServlet 是如何交给tomcat的,以及是如何与spring发生联系的,都在这里完成
//省略
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
@EnableConfigurationProperties({ServerProperties.class})
//上面注解实质上只有@AutoConfigureAfter是boot新增的,其他注解都是spring本来有的或者在spring基础上做的扩展
public class DispatcherServletAutoConfiguration {
/*******DispatcherServlet如何与spring发生联系********/
//省略注解
protected static class DispatcherServletConfiguration {
private final WebMvcProperties webMvcProperties;
private final ServerProperties serverProperties;
//DispatcherServletConfiguration 类只有一个有参构造器,在装配模式NO的情况下,determinCandidateConstructors的时候就可以确定该构造器,并且spring会把两个参数也给这个构造器
public DispatcherServletConfiguration(WebMvcProperties webMvcProperties, ServerProperties serverProperties) {
this.webMvcProperties = webMvcProperties;
this.serverProperties = serverProperties;
}
//把DispatcherServlet 放入spring容器
//在mvc零配置的时候我们是把appContext当作DispatcherServlet 的构造器入参传给DispatcherServlet
//boot中DispatcherServlet 是如何使用到appContext的呢?
//其实是DispatcherServlet 的父类FrameworkServlet实现了ApplicationContextAware接口,spring在初始化的时候会回调此接口把自己的上下文环境传给他
@Bean(name = {"dispatcherServlet"})
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
//省略
return dispatcherServlet;
}
/*******DispatcherServlet如何与spring发生联系********/
/*******DispatcherServlet 是如何交给tomcat的********/
//省略
protected static class DispatcherServletRegistrationConfiguration {
//构造器原理同上
//省略
@Bean(name = {"dispatcherServletRegistration"})
//方法参数是上面这个内部类@Bean放到spring容器的
public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
//把dispatcherServlet和ServerProperties(其实是我们yml文件配置的server.address,server.port等属性)通过构造器给ServletRegistrationBean
ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean(dispatcherServlet, new String[]{this.serverProperties.getServlet().getServletMapping()});
//省略
return registration;
}
}
//到现在为止我们还不知道dispatcherServlet是如何交给tomcat的,注意ServletRegistrationBean这个类
//他的顶级父类如下,一看ServletContextInitializer的onStartup我就懂了,servlet的spi机制而已
public abstract class RegistrationBean implements ServletContextInitializer, Ordered {
public final void onStartup(ServletContext servletContext) throws ServletException {
String description = this.getDescription();
this.register(description, servletContext);
}
this.register(description, servletContext);//这行代码一直点下去会发现如下熟悉的代码
{
String name = this.getServletName();
return servletContext.addServlet(name, this.servlet);
}
}
/*******DispatcherServlet 是如何交给tomcat的********/
}
}
@AutoConfigureAfter注解
DispatcherServletAutoConfiguration 要在ServletWebServerFactoryAutoConfiguration之后被spring实例化, @AutoConfigureAfter是如何控制这些类的顺序的
AutoConfigurationImportSelector类的如下代码
//selectImports方法是由spring的初始化过程的invokeBeanFactoryPostProcessors方法回调的
//该方法在这里就是给传过来的类排个序
public Iterable<Entry> selectImports() {
return (Iterable)this.sortAutoConfigurations().stream().map((importClassName) -> {
return new Entry((AnnotationMetadata)this.entries.get(importClassName), importClassName);
}).collect(Collectors.toList());
}
private List<String> sortAutoConfigurations() {
//省略
return (new AutoConfigurationSorter(this.getMetadataReaderFactory(), autoConfigurationMetadata)).getInPriorityOrder(autoConfigurations);
}
}
public List<String> getInPriorityOrder(Collection<String> classNames) {
//省略
//这里处理@AutoConfigureAfter注解
List<String> orderedClassNames = this.sortByAnnotation(classes, orderedClassNames);
return orderedClassNames;
}
@EnableConfigurationProperties注解
@EnableConfigurationProperties({ServerProperties.class}) --->
@Import({EnableConfigurationPropertiesImportSelector.class})
public @interface EnableConfigurationProperties {
Class<?>[] value() default {};
}
class EnableConfigurationPropertiesImportSelector implements ImportSelector {
private static final String[] IMPORTS = new String[]{EnableConfigurationPropertiesImportSelector.ConfigurationPropertiesBeanRegistrar.class.getName()};
public String[] selectImports(AnnotationMetadata metadata) {
return IMPORTS;
}
//该类被EnableConfigurationPropertiesImportSelector import了
//并且该类是ImportBeanDefinitionRegistrar ,会回调registerBeanDefinitions函数
public static class ConfigurationPropertiesBeanRegistrar implements ImportBeanDefinitionRegistrar {
public ConfigurationPropertiesBeanRegistrar() {
}
//metadata在这里是DispatcherServletAutoConfiguration的注解信息
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//拿到配置集合遍历
this.getTypes(metadata).forEach((type) -> {
//为每一个配置文件注册bd
this.register(registry, (ConfigurableListableBeanFactory)registry, type);
});
}
private List<Class<?>> getTypes(AnnotationMetadata metadata) {
//只关心DispatcherServletAutoConfiguration的EnableConfigurationProperties的注解信息
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(EnableConfigurationProperties.class.getName(), false);
//返回@EnableConfigurationProperties里的怕配置文件集合
return this.collectClasses(attributes != null ? (List)attributes.get("value") : Collections.emptyList());
}
}
}
总结
自动配置原理:spring.factories 用ImportSelector放入spring容器
DispatcherServlet关联spring:@Bean将DS放入spring容器,ApplicationContextAware接口将spring的appContext给DS
DispatcherServlet关联tomcat:servlet3.0 SPI扩展机制