1.一切起源之@SpringBootApplication
SpringBoot全局配置文件application.properties或application.yml可以配置哪些属性 参考文档
作为SpringBoot项目的入口,@SpringBootApplication起到了关键性的作用,另外需要注意的是SpringBoot所有关于自动配置的源码都在spring-boot-autoconfigure-x.x.x.x.jar里面
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //声明这是一个SpringBoot应用配置类
@EnableAutoConfiguration //开启自动配置,尝试去自动配置你可能需要的的Beans
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //开启包扫描,并且指定扫描的范围
public @interface SpringBootApplication {
我们可以看到上面SpringBoot开启了自动配置,使用了@EnableAutoConfiguration注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
@EnableAutoConfiguration内部又通过@Import注解引入了EnableAutoConfigurationImportSelector资源,看名字EnableAutoConfigurationImportSelector大概是开启了自动配置引入选择器,那它到底是在选择什么呢?
public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
public EnableAutoConfigurationImportSelector() {
}
protected boolean isEnabled(AnnotationMetadata metadata) {
return this.getClass().equals(EnableAutoConfigurationImportSelector.class) ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true;
}
}
点击进入后发现它继承自AutoConfigurationImportSelector选择器
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private static final String[] NO_IMPORTS = new String[0];
private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
public AutoConfigurationImportSelector() {
}
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
//加载自动配置元数据,即加载自动配置所有组件相关的基础类
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取候选的配置,即哪些自动配置需要生效
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//移除重复的配置
//内部代码使用一个ArrayList去构建一个LinkedHashSet,再将LinkedHashSet转为ArrayList就实现了去重功能,因为LinkedHashSet元素唯一
configurations = this.removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
//移除配置,spring.auto.exclude='some component exclude'
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return (String[])configurations.toArray(new String[configurations.size()]);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}
//加载候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//所有候选的自动配置都通过SpringFactoriesLoader加载
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
而在AutoConfigurationImportSelector类中我们发现存在selectImports方法,看名字我们大概可以猜到这里回去动态的选择导某些资源。而我们查看方法内部发现,
//加载器
public abstract class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
//资源加载位置,当前org.springframework.boot.autoconfigure项目下的META-INF/spring.factories
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
//加载META-INF/spring.factories的所有配置
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
spring.factories文件内部定义了所有的XXXAutoConfiguration配置类,因此加载过程会将所有的配置类加载到Spring容器中
此时对于spring.factories里面的所有配置,为了更好的讲解。我们一模板引擎Thymeleaf继续向大家分析Springboot自动配置。
spring.factories里面存在如下内容:
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
我们继续进入ThymeleafAutoConfiguration查看内容
@Configuration //声明这是个配置类
@EnableConfigurationProperties({ThymeleafProperties.class}) //引入ThymeleafProperties类里面的配置
@ConditionalOnClass({SpringTemplateEngine.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class}) //在WebMvcAutoConfiguration加载之后再加载此类
public class ThymeleafAutoConfiguration {
public ThymeleafAutoConfiguration() {
}
@Configuration
@ConditionalOnWebApplication //web项目条件下启用
protected static class ThymeleafResourceHandlingConfig {
protected ThymeleafResourceHandlingConfig() {
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledResourceChain
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
}
@Configuration
@ConditionalOnJava(JavaVersion.EIGHT)
@ConditionalOnClass({Java8TimeDialect.class})
protected static class ThymeleafJava8TimeDialect {
protected ThymeleafJava8TimeDialect() {
}
@Bean
@ConditionalOnMissingBean
public Java8TimeDialect java8TimeDialect() {
return new Java8TimeDialect();
}
}
@ConfigurationProperties(prefix = "spring.thymeleaf" )//定义自动以配置前缀
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/"; //页面资源默认路径
public static final String DEFAULT_SUFFIX = ".html"; //页面资源默认后缀名
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML5";
private Charset encoding;
private MimeType contentType;
private boolean cache;
private Integer templateResolverOrder;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enabled;
至此,SpringBoot自动配置结束,最后上一张自动配置工作原理图