Spring Boot 探索之旅(三)——Boot项目启动运行原理
一、boot项目核心注解@SpringBootApplication
首先进入SpringBootApplication源码分析
@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 {
/**
* 按类排除
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**
* 按类名排除
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
/**
* 扫描具有componenScan注解的类名
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* 扫描具有componenScan注解的类
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
再进入EnableAutoConfiguration源码分析
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)//导入配置选择器
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* 按类解除自动配置
*/
Class<?>[] exclude() default {};
/**
*按类名解除自动配置
*/
String[] excludeName() default {};
}
对导入的AutoConfigurationImportSelector分析
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
private static final String[] NO_IMPORTS = {};
private static final Log logger = LogFactory
.getLog(AutoConfigurationImportSelector.class);
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//如果开关关闭,则不做任何自动配置
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//通过类加载器获取默认配置数据
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//排除解除自动配置的类
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
@Override
public Class<? extends Group> getImportGroup() {
return AutoConfigurationGroup.class;
}
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
true);
}
return true;
}
/**
* Return the appropriate {@link AnnotationAttributes} from the
* {@link AnnotationMetadata}. By default this method will return attributes for
* {@link #getAnnotationClass()}.
* @param metadata the annotation metadata
* @return annotation attributes
*/
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes,
() -> "No auto-configuration attributes found. Is "
+ metadata.getClassName() + " annotated with "
+ ClassUtils.getShortName(name) + "?");
return attributes;
}
/**
* Return the source annotation class used by the selector.
* @return the annotation class
*/
protected Class<?> getAnnotationClass() {
return EnableAutoConfiguration.class;
}
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), 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;
}
。。。。
探究AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader)
final class AutoConfigurationMetadataLoader {
//在autoconfiguration依赖中
protected static final String PATH = "META-INF/"
+ "spring-autoconfigure-metadata.properties";
private AutoConfigurationMetadataLoader() {
}
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
//加载默认配置
try {
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils
.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException(
"Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
static AutoConfigurationMetadata loadMetadata(Properties properties) {
return new PropertiesAutoConfigurationMetadata(properties);
}
/**
* {@link AutoConfigurationMetadata} implementation backed by a properties file.
*/
private static class PropertiesAutoConfigurationMetadata
implements AutoConfigurationMetadata {
private final Properties properties;
PropertiesAutoConfigurationMetadata(Properties properties) {
this.properties = properties;
}
@Override
public boolean wasProcessed(String className) {
return this.properties.containsKey(className);
}
@Override
public Integer getInteger(String className, String key) {
return getInteger(className, key, null);
}
@Override
public Integer getInteger(String className, String key, Integer defaultValue) {
String value = get(className, key);
return (value != null) ? Integer.valueOf(value) : defaultValue;
}
@Override
public Set<String> getSet(String className, String key) {
return getSet(className, key, null);
}
@Override
public Set<String> getSet(String className, String key,
Set<String> defaultValue) {
String value = get(className, key);
return (value != null) ? StringUtils.commaDelimitedListToSet(value)
: defaultValue;
}
@Override
public String get(String className, String key) {
return get(className, key, null);
}
@Override
public String get(String className, String key, String defaultValue) {
String value = this.properties.getProperty(className + "." + key);
return (value != null) ? value : defaultValue;
}
}
}
查看spring-autoconfigure-metadata.properties文件
二、Spring Boot核心Main方法
** 分析SpringApplication.run方法**
public ConfigurableApplicationContext run(String... args) {
//StopWatch检查项目启动所需时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//创建项目上下文对象
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 从配置中获取SpringApplicationRunListener实现类并实例化,
// 最终把所有这些实例包装到一个SpringApplicationRunListeners实例来使用
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 这里创建应用上下文
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
还没有评论,来说两句吧...