spring boot 项目都有个启动类,如下:
@SpringBootApplication public class DemoApplication{ public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
写在前面:
自动配置的类的加载和配置:
SpringFactoriesLoader.loadFactoryNames() 方法加载所有的META-INF/spring.factories 文件,这个文件就是配置要自动配置的类。
文件的配置包含了:ApplicationListener, ApplicationContextInitializer,AutoConfigurationImportFilter,EnableAutoConfiguration 等等,可以自己去看一下。
这个文件就是 spring-boot-autoconfigure-1.5.9.RELEASE.jar!/META-INF/spring.factories
1、SpringApplication.run() 方法:
跟踪到实现:
public static ConfigurableApplicationContext run(Object[] sources, String[] args) { /先new 一个SpringApplication 对象,然后调用run 方法。 return (new SpringApplication(sources)).run(args); }
1.1 创建new SpringApplication(sources) 对象:
public SpringApplication(Object... sources) { //初始化 this.initialize(sources); } //初始化 initialize(sources) private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } //通过"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" 这两个类是是否存在 //创建一个WebApplicationContext还是一个标准的Standalone 应用的ApplicationContext类型 this.webEnvironment = this.deduceWebEnvironment(); //通过SpringFactoriesLoader 在classpath 中查找并加载所有可用的 ApplicationContextInitializer的class this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //通过SpringFactoriesLoader 在classpath 中查找并加载所有可用的 ApplicationListener的class this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //推判出main 方法的启动类 this.mainApplicationClass = this.deduceMainApplicationClass(); }
2、 SpringApplication 创建后就调用了 run 方法:
public ConfigurableApplicationContext run(String... args) { //监控每个任务执行时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; //设置Headless模式,默认为true configureHeadlessProperty(); //查找通过 SpringFactoriesLoader 加载的所有 SpringApplicationRunListener 类,并调用starting 方法 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ////封装启动参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //准备运行环境,配置当前Spring Boot 应用将要使用的environment,在方法中调用configureEnvironment() 装载PropertySource 和 Profile //并在此方法中调用所有 listeners 的environmentPrepared方法,通知当前SpringBoot 的Environment 装备好了。 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //加载打印的Banner Banner printedBanner = printBanner(environment); //根据初始化是否是webEnvironment,创建相应的ApplicationContext context = createApplicationContext(); //异常处理 analyzers = new FailureAnalyzers(context); //准备 ApplicationContext prepareContext(context, environment, listeners, applicationArguments,printedBanner); //这个就是调用ApplicationContext的refresh 方法,这个很熟悉吧,就是spring 的 Ioc //最后调用了 ConfigurationClassParser.processDeferredImportSelectors() 方法,是加载 selectors 的。可以通过debug 找调用链 //通过调用解析 @SpringBootApplication 注解的@Import 元注解的导入类,并调用 selectImports 方法 refreshContext(context); //执行ioc 容器中的 ApplicationRunner 和 CommandLineRunner 的run 方法,可以自己定义这两个类的子类,在加载完后自动调用 afterRefresh(context, applicationArguments); //调用所有的 SpringApplicationRunListeners ,告知启动完了 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } return context; }catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
下面就对准备ApplicationContext 和 @Import 的导入类进行分析
准备ApplicationContext 方法处理过程:
//准备ApplicationContext private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //设置环境,资源applicationContext 的类加载器,把生成beanName 的类( BeanNameGenerator )注入到上下文 context.setEnvironment(environment); //对ApplicationContext 进一步加工 //BeanNameGenerator 注入 //resourceLoader和calssLoader 设置 postProcessApplicationContext(context); //使用 SpringFactoriesLoader 加载的所有 ApplicationContextInitializer,对ApplicationContext 进一步设置 applyInitializers(context); //调用所有的 SpringApplicationRunListener 的contextPrepared 方法,告知上下文已经准备好 listeners.contextPrepared(context); //日志处理 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } //源码注释: Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { //注册banner context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); //把当前的source(当前的启动类,也可以是想让注入的类)注入到spring 容器,并且通过source 注解的信息获取元数据。 load(context, sources.toArray(new Object[sources.size()])); //调用所有的 SpringApplicationRunListeners contextLoaded 方法,告知applicationContext 已经装填完毕 listeners.contextLoaded(context); } //load 方法: protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } //创建 BeanDefinitionLoader, 包含了 AnnotatedBeanDefinitionReader XmlBeanDefinitionReader ClassPathBeanDefinitionScanner 提供各种情况的 bean 读取方式 BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } //加载的方法 loader.load(); } //loader.load(); private int load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof Class<?>) { //启动时使用的这个加载方式 return load((Class<?>) source); } if (source instanceof Resource) { //从 resource 加载 return load((Resource) source); } if (source instanceof Package) { //从包加载,就是scanner扫描 return load((Package) source); } if (source instanceof CharSequence) { //从string 加载 return load((CharSequence) source); } throw new IllegalArgumentException("Invalid source type " + source.getClass()); } //load(class) 方法 private int load(Class<?> source) { if (isGroovyPresent()) { // Any GroovyLoaders added in beans{} DSL can contribute beans here if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); load(loader); } } if (isComponent(source)) { //这个才是实现的方法,一层一层往下找,最后找到的是 annotatedReader.registerBean() 方法 this.annotatedReader.register(source); return 1; } return 0; } /** * Register a bean from the given bean class, deriving its metadata from class-declared annotations. * 翻译下:从给定的bean class 注册这个bean,通过这个class 定义的annotations 获取这个bean的元数据。这下很明白了,@SpringBootApplication 相关注解就是在这解析的。 */ public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) { //创建注解的BeanDefinition,构造方法中创建了一个StandardAnnotationMetadata,用来存放annotatedClass 的注解 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); //通过 Conditional 判断是否不加载元数据 if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } //解析元数据的scope ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); //bean 名称,就是启动类的bean demoApplication String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); //metadata 的底层元素是否有Lazy Primary DependsOn Role Description 等注解或者元注解,如果有则set 相关属性(请看源码) AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); //注入bean时, if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } //创建 BeanDefinitionHolder,这个通过beanName aliases 持有bean BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); //申请一个 definitionHolder 的代理对象, definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); //把beanDefinition 放入到spring 容器中 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
ApplicationContext 准备完毕后,就调用Spring启动时调用的refreshContext(context) 方法,自动配置的类就在这里面被调用的。
@SpringBootApplication 注解的@Import 元注解的导入类,并调用 selectImports 方法
//autoConfiguration 方法,参数就是启动类 DemoApplication 的注解 public String[] selectImports(AnnotationMetadata annotationMetadata) { //没有自动配置的就返回 if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { // META-INF/spring-autoconfigure-metadata.properties 并把这个文件的配置Properties成,然后创建 PropertiesAutoConfigurationMetadata 对象并返回 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); //annotationMetadata 的属性,这里就是把 @SpringBootApplication 注解的exclude 值,解析出来。 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 使用classLoader 加载所有的 META-INF/spring.factories 文件,并从中解析出 EnableAutoConfiguration.class 子类。 //是使用SpringFactoriesLoader.loadFactoryNames() 方法,在前面加载 applyInitializers 也是使用同样方法,只是解析的类不一样。 List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes); //去重 configurations = removeDuplicates(configurations); //排序,先按照字母表顺序排,再按照 order 注解顺序排,最后处理 @AutoConfigureBefore @AutoConfigureAfter 注解1 configurations = sort(configurations, autoConfigurationMetadata); //获取到 annotationMetadata 属性排除加载的的类 Set<String> exclusions = getExclusions(annotationMetadata, attributes); //如果排除的类存在,且不在 configurations 集合中,那么就要 IllegalStateException 运行时异常 checkExcludedClasses(configurations, exclusions); //删除掉忽略自动配置的类 configurations.removeAll(exclusions); //过滤掉不用自动配置的类。这个filter 方法就是我们自己配置的 Condition matchs() 方法调用的地方 configurations = filter(configurations, autoConfigurationMetadata); //开始自动配置 fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } } //过滤掉不用怎么配置的类,返回的是要自动配置的 private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); //自动配置类全类名 String[] candidates = configurations.toArray(new String[configurations.size()]); //自动配置的类是否要跳过自动配置 boolean[] skip = new boolean[candidates.length]; //如果有跳过自动配置的,那么就是true了,如果所有的自动配置类都匹配上了,那么就是false,就可以快速返回,不用把不用自动配置的类过滤掉 boolean skipped = false; //通过pringFactoriesLoader.loadFactories() 获取 AutoConfigurationImportFilter 对象,所有的candidates 都要通过filter 过滤一遍,找出确定要自动配置的类 //getAutoConfigurationImportFilters() 方法,就是SpringFactoriesLoader.loadFactories() 方法加载所有 AutoConfigurationImportFilter.class 的类 for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { //设置resource, classLoader 属性 invokeAwareMethods(filter); //这个方法就是调用 Condition match() 方法的地方 boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; skipped = true; } } } //如果所有的配置都没有跳过自动配置,那么直接返回 if (!skipped) { return configurations; } //下面的代码就是把不用自动配置的类去掉,剩下的类都是要自动配置的 List<String> result = new ArrayList<String>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) { result.add(candidates[i]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return new ArrayList<String>(result); } //来看看filter.match() 方法是怎么匹配的实现。 在spring.factories 配置中只配置了一个AutoConfigurationImportFilter 类OnClassCondition。即调用这个类的 match()方法。 @Override public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { //获取条件判断的类 ConditionEvaluationReport report = getConditionEvaluationReport(); //把全类名,转化成 ConditionOutcome 对象。在这个转化中处理match的 ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata); boolean[] match = new boolean[outcomes.length]; for (int i = 0; i < outcomes.length; i++) { //判断是否匹配 match[i] = (outcomes[i] == null || outcomes[i].isMatch()); if (!match[i] && outcomes[i] != null) { logOutcome(autoConfigurationClasses[i], outcomes[i]); if (report != null) { report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]); } } } return match; } //把自动配置的全类名转化成ConditionOutcome对象,并验证是否要自动配置 private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { //把 autoConfigurationClasses 分成两部分来处理。 // Split the work and perform half in a background thread. Using a single // additional thread seems to offer the best performance. More threads make // things worse int split = autoConfigurationClasses.length / 2; OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split, autoConfigurationMetadata); OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split, autoConfigurationClasses.length,autoConfigurationMetadata, this.beanClassLoader); //把自动配置的全类名转化成ConditionOutcome对象,这里看OnClassCondition内部类StandardOutcomesResolver.resolveOutcomes() 方法 ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes(); ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes(); //合并处理完成后的结果 ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length]; System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length); System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length); return outcomes; } //resolveOutcomes() 方法调用下面两个方法实现的 private ConditionOutcome[] getOutcomes(final String[] autoConfigurationClasses, int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) { ConditionOutcome[] outcomes = new ConditionOutcome[end - start]; for (int i = start; i < end; i++) { String autoConfigurationClass = autoConfigurationClasses[i]; //获取自动配置类的 ConditionalOnClass 注解属性的值,即如果要自动配置,那么就要有这些类的存在。 Set<String> candidates = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnClass"); if (candidates != null) { //如果有 ConditionalOnClass 属性配置,那么就验证是否有这些类的存在。 outcomes[i - start] = getOutcome(candidates); } } return outcomes; } private ConditionOutcome getOutcome(Set<String> candidates) { try { //通过MatchType.MISSING 方法进行验证 candidates 类是否有不存在的,如果有不存在的,那么就返回ConditionOutcome.noMatch(false,"message") 对象。到这里就完成了。 List<String> missing = getMatches(candidates, MatchType.MISSING,this.beanClassLoader); if (!missing.isEmpty()) { return ConditionOutcome.noMatch( ConditionMessage.forCondition(ConditionalOnClass.class) .didNotFind("required class", "required classes") .items(Style.QUOTE, missing)); } } catch (Exception ex) { // We'll get another chance later } return null; }
这里只看了ConditionalOnClass 的match() 方式,还有其它的match() ,可以自己查看。
spring-boot-autoconfigure-1.5.9.RELEASE.jar org.springframework.boot.autoconfigure.condition 包中还有很多 conditional 的定义,可以看看具体的实现。