SpringBoot——启动与自动配置类查找
今天学习一下SpringBoot的启动及自动配置,由于没有参与过springBoot项目开发,
所以初次学习的主要目标:将SpringBoot中的自动配置与启动与之前学习的Spring与SpringMVC实现联系起来。弄清楚SpringBoot中的:
- SpringIOC容器初始化(怎样实现自动配置的)
- SpringAOP支持
- Spring事务支持
- SpringMVC组件初始化
- Tomcat启动
一、SpringBoot启动流程
@SpringBootApplication public class App { public static void main( String[] args ) { //springboot应用启动 SpringApplication.run(App.class,args); } } /*
* org.springframework.boot.SpringApplication#run()
*/ public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
1、SpringApplication的初始化
初始化了6个属性:
- resourceLoader:资源加载器,初始化时一般为null
- primarySources:启动时配置文件Configuration
- webApplicationType:容器类型;
- initalizers:实例化多个与容器初始化有关的组件;
- listeners:实例化多个应用监听器;
- mainApplicationClass:main方法所在的类的Class实例。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { //null this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //启动时配置Configuration this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //容器类型,三个枚举类型,判断顺序 // ① 反应式web容器:WebApplicationType.REACTIVE:项目工程中包含DispatcherHandler.class,不包含DispatcherServlet.class、ServletContainer.class // ② 不是web应用:WebApplicationType.NONE:项目工程中不包含ConfigurableWebApplicationContext.class、Servlet.class // ③ 响应式web容器:WebApplicationType.SERVLET:不是上面两种情况,则响应式web容器启动 this.webApplicationType = WebApplicationType.deduceFromClasspath(); //实例化多个与IOC容器初始化有关的组件 // 具体实例化所有jar包下的/META-INF/spring.factories文件中,ApplicationContextInitializer.class全限定名指定的class数组中所以Class setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //实例化多个应用监听器 // 具体实例化所有jar包下的/META-INF/spring.factories文件中,ApplicationListener.class全限定名指定的class数组中所以Class setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //main方法所在的类的Class实例 this.mainApplicationClass = deduceMainApplicationClass(); }
先介绍下getSpringFactorieInstances()方法:springboot中SPI(服务发现接口)机制的实现,主要是根据/META-INF/spring.factories中寻找并创建对应的服务实例。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { //获取类加载器,(SPI打破类加载的双亲委派模型) ClassLoader classLoader = getClassLoader(); // 从所用/META-INF/spring.factories中找到type对应的class集合,后面SpringFactoriesLoader是Spring-core.java中的类。 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 实例化class类型集合(parameterTypers:class的有参构造器中参数类型;args:构造器传参) List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //优先级排序(BeanFactoryPostProcessor时提到过的顺序:先PriorityOrdered,后Ordered,其他) AnnotationAwareOrderComparator.sort(instances); return instances; }
例如上面的:getSpringFactoriesInstances(ApplicationListener.class)
//spring-boot-autoconfigure.jar/META-INF/spring.factories //Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer
2、SpringApplication.run()运行的流程
public ConfigurableApplicationContext run(String... args) { // ① 简单的秒表,记录服务启动到关闭的时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; // ② 异常记录器 spring.factories中SpringBootExceptionReporter.class对应的类型实例 // org.springframework.boot.diagnostics.FailureAnalyzers的实例 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // ③ 启动抽象窗口工具包支持:java.awt.headless = true // 无显示设备,鼠标,键盘时,awt+Swing可进行窗口编程(window+frame等) configureHeadlessProperty(); // ③ 应用监听器 spring.factories中SpringApplicationRunListener.class对应的类型实例 // org.springframework.boot.context.event.EventPublishingRunListener实例 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // ④ 初始化环境变量 // 根据上面容器类型创建对应的创建变量实例 // 设置defaultProperties(springApplication.set)、args(命令行参数)、profiles(spring.profiles.active)属性 // 绑定环境变量到监听器+spring.main(默认当前SpringApplication实例) ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 设置spring.beaninfo.ignore(默认true)到环境变量中 configureIgnoreBeanInfo(environment); // 打印/不打印环境到控制台、日志 Banner printedBanner = printBanner(environment); // ⑤ 根据对应容器类型创建容器 // 响应式web容器:AnnotationConfigServletWebServerApplicationContext // ① 父类的构造方法中创建DefaultListableBeanFactory // ② reader 注册注解注入的Bean后置处理器到IOC容器中AutowiredAnnotationBeanPostProcessor
// BeanFactory后置处理器ConfigurationClassPostProcessor,后面发现这个就是自动配置实现的类 // ③ scanner 设置环境变量、resourceLoader、includeFilters(Spring的@Component+JDK的@Named) context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //⑥ 初始化容器context的一部分属性 // ① 环境变量覆盖 // ② 将容器绑定到初始化组件(initializers)、监听器(listeners)中// ③ 注册单例 命令行参数的包装实例applicationArguments、printedBanner // ④ 设置懒加载则注册懒加载BeanFactory后置处理器 LazyInitializationBeanFactoryPostProcessor // ⑤ 不允许BeanDefinition覆盖 // ⑥ 将配置resource(包括MainClass)加载到容器中,MainClass(App.class)解析成一个AnnotatedGenericBeanDefinition // ⑦ 将listeners中ApplicationContextListener类型的监听器注册到容器中 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //⑦ 容器初始化 主要是AnnotationConfigServletWebServerApplicationContext的父类 // ServletWebServerApplicationContext,这个第三节研究 refreshContext(context); //⑧ 空方法 afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { // 打印日志 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //监听器启动 listeners.started(context); //唤醒runners 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; }
小结:熟悉了大致流程:发现核心的实现还是在⑦ 容器初始化中:refreshContext()。
- 容器的初始化
- tomcat的嵌入
- 两个组件initalizers、listeners的作用
3、Springboot容器初始化——refreshContext()
refreshContext() : 容器初始化+优雅停机
/* org.springframework.boot.SpringApplication#refreshContext */ private void refreshContext(ConfigurableApplicationContext context) { //容器初始化 refresh((ApplicationContext) context); if (this.registerShutdownHook) { try { // JDK的shutdownHook关闭钩子, // 作用:优雅停机。调用系统退出方法(关机注销)时,线程还在跑,但不提供服务,设定一个超时时间,到时间后停机。 // kill pid(注意:不能kill -9 pid) context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } } protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext); //容器初始化 refresh((ConfigurableApplicationContext) applicationContext); } protected void refresh(ConfigurableApplicationContext applicationContext) { //容器初始化 //AnnotationConfigServletWebServerApplicationContext.refresh() applicationContext.refresh(); }
AnnotationConfigServletWebServerApplicationContext.refresh(),
查看AnnotationConfigServletWebServerApplicationContext的类图,发现springboot相比于spring实现了一个ServletWebServerApplicationContext
如果观看AnnotationConfigservletWebServerApplicationContext源码,发现具体逻辑实现都在ServletWebServerApplicationContext中,所以主要学习ServletWebServerApplicationContext的源码:ServletWebServerApplicationContext.refresh();
/* org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#refresh */ public final void refresh() throws BeansException, IllegalStateException { try { //AbstractApplicationContext.refresh() super.refresh(); } catch (RuntimeException ex) { //关闭释放web服务(tomcat、jetty等) stopAndReleaseWebServer(); throw ex; } }
结合之前的SpringIOC——refresh()分析,装饰者模式(继承实现)有对哪些模块有增强。先给出AbstractApplicationContext.refresh()。仅说明增强功能。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // ② IOC初始化前的装备(配置环境参数、创建监听器、事件容器) // 增强:scanner缓存清理 prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { // 彻底重写 postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); //增强:初始化了一个web服务:createWebServer(tomcat、jetty等),并启动 onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); //增强:webServer未启动时,重新启动 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
综上:找到了tomcat启动的位置,但是没有找到自动配置的位置,可能是postProcessBeanFactory(beanFactory)
/* org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext */ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //注册了一个Bean后置处理器WebApplicationContextServletContextAwareProcessor //这个Bean后置处理器逻辑很简单:仅有一个前置方法 // servletContextAware类型的bean,bean.set(servletContext) // servletConfigAware类型的bean,bean.set(servletConfig) beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this)); //忽略实现接口ServletContextAware的Bean //跟上面的Bean后置处理器冲突,应该是版本升级加的吧 beanFactory.ignoreDependencyInterface(ServletContextAware.class); registerWebApplicationScopes(); } private void registerWebApplicationScopes() { // 允许用户自定义scope(不能与自带的singleton,prototype冲突) // 注册web的作用域scope(session、request) // 将scope注册进IOC容器中 ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory()); WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory()); existingScopes.restore(); }
综上:还是没有找到自动配置实现的地方,只能IDEA debug一行一行的找了,最终发现
invokeBeanFactoryPostProcessors(beanFactory):这一行执行完,容器中多了100多个BeanDefinition,也就是说是BeanFactory的后置处理器实现自动配置的。
最终找到了ConfigurationClassPostProcessor,这个BeanFactoryPostProcessor是在AnnotationConfigservletWebServerApplicationContext初始化时注册入到容器中的
/* org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext#AnnotationConfigServletWebServerApplicationContext() */ public AnnotationConfigServletWebServerApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } /* * 下面是spring-context.jar中的源码,也就是自动加载还是依托于spring源码实现的 */ /* org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment) */ public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } /*org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) */ public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8); if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { //BeanFactory后置处理器:会对class上的@Configuration、@ComponentScan、@Component、@Import、@ImportResource注解解析 RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { //Bean后置处理器:在bean实例化后实现依赖注入的(@Autowired注解) RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); try { def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader())); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex); } def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }
ConfigurationClassPostProcessor.processConfigBeanDefinitions():解析@Configuration注解类中的@Bean到容器BeanDefinition容器中(属于Spring的源码)
二、自动配置
自动配置配置代码有点复杂,主要看看@SpringBootApplication的实现
1、@SpringBootApplication注解
@SpringBootApplication是一个组合注解,主要是@SpringBootConfiguration+@EnableAutoConfiguration+@ComponentScan
@SpringBootConfiguration == @Configuration
@EnableAutoConfiguration = @AutoConfigurationPackage +@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage = @Import(AutoConfigurationPackages.Registrar.class)
综上:@SpringBootApplication = @Configuration + @Import(AutoConfigurationPackages.Registrar.class)+@Import(AutoConfigurationImportSelector.class)+@ComponentScan
顺序ConfigurationClassPostProcessor找到@ComponentScan、@Import的解析
ConfigurationClassPostProcessor.processConfigBeanDefinitions()-->parser.parse(candidates)
ConfigurationClassParser.parse-->ConfigurationClassParser.processConfigurationClass->ConfigurationClassParser.doProcessConfigurationClass()
protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass, filter); } // 处理@PropertySource注解 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // 处理componentScans注解 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { //如果bdCand也被@Configuration注解,解析
parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // 处理Import注解 processImports(configClass, sourceClass, getImports(sourceClass), filter, true); // 处理@ImportResource注解 AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // 处理@Configuration中的@Bean注解 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // 处理接口默认的方法 @Import(AutoConfigurationPackages.Registrar.class)
// AutoConfigurationPackages.Registrar 的接口有默认方法,
// 将MainClass的basePackage封装成一个BeanDefinition放入到IOC容器中,并不是扫描basePackage,仅仅是一个记录的作用 processInterfaces(configClass, sourceClass); // 处理超类 if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } return null; }
@ComponentScan注解解析:
basePackage/basePackageClasses未设置时,扫描@ComponentScan所注解的类所在的包下的所有class文件,
@Component注解的class文件,生成BeanDefinition放入IOC容器中
SpringBoot未配置basePackage、basePackageClasses,所以会扫描MainClass所在包下的所有class文件。
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { //@ComponentScan注解对应一个ClassPathBeanDefinitionScanner实例 //setUserDefaultFilters:是否使用默认过滤器Filters,默认使用 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); //setBeanNameGenerator:设置默认的beanName生成器,默认使用BeanNameGenerator.class Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass)); //setScopedProxyMode:设置是否为检测组件生成代理 ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy"); if (scopedProxyMode != ScopedProxyMode.DEFAULT) { scanner.setScopedProxyMode(scopedProxyMode); } else { Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver"); scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass)); } //setResourcePattern:扫描包下源文件格式 默认"**/*.class" scanner.setResourcePattern(componentScan.getString("resourcePattern")); //includeFilter:扫描组件过滤器,符合includeFilter条件的类,生成BeanDefinition for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } //excludeFilter:扫描组件反向过滤器,符合excludeFilter条件的类,不生成BeanDefinition for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); } } //lazyInit:懒加载 默认关闭 boolean lazyInit = componentScan.getBoolean("lazyInit"); if (lazyInit) { scanner.getBeanDefinitionDefaults().setLazyInit(true); } //扫描的包basePackages下class文件 Set<String> basePackages = new LinkedHashSet<>(); String[] basePackagesArray = componentScan.getStringArray("basePackages"); for (String pkg : basePackagesArray) { String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); Collections.addAll(basePackages, tokenized); } //扫描的basePackageClasses所在包下class文件 for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } //如果basePackages,basePackageClasses未设置, // 扫描@ComponentScan所注解的类所在包下的class文件: // 这里就是Springboot扫描MainClass同包下的Bean的原因 if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(declaringClass)); } scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) { return declaringClass.equals(className); } }); //scanner.do(basePackages):熟悉的spring源码,扫描basePackages下的class文件(includeFilters = @Component)生成组件 return scanner.doScan(StringUtils.toStringArray(basePackages)); }
@Import解析:
- DeferredImportSelector放入容器ConfigurationClassParser中的deferredImportSelectors中
- ImportBeanDefinitionRegistrar放入ConfigurationClass的importBeanDefinitionRegistrars容器中
- 其他类型@Import==@Configuration处理
/* org.springframework.context.annotation.ConfigurationClassParser#processImports */ private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { //校验@Import()如果括号中值为空直接返回 if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { //@Import()指定类型是ImportSelector类型 Class<?> candidateClass = candidate.loadClass(); //初始化ImportSelector实例 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredImportSelector) { // 指定类型再细分为DeferredImportSelector类型 // springboot的注解@Import(AutoConfigurationImportSelector.class) // 将AutoConfigurationImportSelector实例放入到 // ConfigurationClassParser中的deferredImportSelectors容器中 this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { //@Import()指定类型是ImportBeanDefinitionRegistrar类型时 //springboot的注解@Import(AutoConfigurationPackages.Registrar.class) Class<?> candidateClass = candidate.loadClass(); //创建一个ImportBeanDefinitionRegistrar实例, // 放入到ConfigurationClass的importBeanDefinitionRegistrars容器中 // ConfigurationClass是@Configuration注解的类的元数据+beanName的封装类型 ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // 指定类不是上两种类型,将@Import视为@Configuration处理 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
@Import+@ComponentScan解析完,后退到ConfigurationClassParser.parse方法
public void parse(Set<BeanDefinitionHolder> configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { //@注解解析(@PropertySource、@ComponentScan、@Import、@ImportResource) parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } //springboot自动配置 this.deferredImportSelectorHandler.process(); }
this.deferredImportSelectorHandler.process();
调用AutoConfigurationImportSelector.selectImports()方法返回/META-INF/spring.factories中EnableAutoConfiguration对应的class数组
将每个文件视作为一个@Configuration注解的class文件进行解析,解析生成BeanDefinition
/* org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler#process */ public void process() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; try { if (deferredImports != null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); deferredImports.forEach(handler::register); handler.processGroupImports(); } } finally { this.deferredImportSelectors = new ArrayList<>(); } } /* org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#register*/ public void register(DeferredImportSelectorHolder deferredImport) { //调用ImportSelector.getImportGroup返回group类型 //springboot: AutoConfigurationImportSelector.getImportGroup==AutoConfigurationGroup.class Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup(); //将group转换成一个DeferredImportSelectorGrouping类型grouping DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent( (group != null ? group : deferredImport), key -> new DeferredImportSelectorGrouping(createGroup(group))); //将deferredImport放入到grouping.deferredImports容器中 //这里还是回忆一下springboot的deferredImport是AutoConfigurationImportSelector、ConfigurationClass的封装器 grouping.add(deferredImport); //将ConfigurationClass放入到ConfigurationClasses容器中, //springboot:MainClass放入到ConfigurationClasses容器中 this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass()); } /* org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports */ public void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate<String> exclusionFilter = grouping.getCandidateFilter(); //grouping.getImports() == <configurationClass,importSelect.selectImports(configurationClass)> //selectImports(configurationClass) ==SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, getBeanClassLoader()) //即这里遍历的是/MATE-INF/spring.factories中EnableAutoConfiguration对应的class数组 //将每个class视作为一个@Import注解解析 // ① class是ImportSelector类型,加入到ConfigurationClassParser中的deferredImportSelectors容器中 // ② ImportBeanDefinitionRegistrar,放入到ConfigurationClass的importBeanDefinitionRegistrars容器中 // ③ 不是上面两种类型,就视为一个@Configuration注解的配置文件类解析 grouping.getImports().forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); try { processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter), Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)), exclusionFilter, false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } }
最后看下AutoConfigurationImportSelector.selectImports()实现
/* org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports */ public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry( AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } 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); //@Condition注解筛选 configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } 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; } protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
spring-boot-autoconfigure-2.1.3.RELEASE.jar!/META-INF/spring.factories中自动配置class数组
总共有118个class,列举spring相关的自动配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
118个class并不是都有效,还需要经过@Condition中条件筛选
/* org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#filter */ private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = StringUtils.toStringArray(configurations); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; //注意filters也是在spring.factories中指定的 //默认三个OnBeanCondition,OnClassCondition,OnWebApplicationCondition即只有三个注解有效@ConditionOnBean @ConditionOnClass @ConditionOnWebApplication for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); //Condition条件判断 boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true;//没通过的打标true candidates[i] = null; skipped = true; } } } if (!skipped) { //所有class都满足各自的Condition return configurations; } List<String> result = new ArrayList<>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) { //满足条件的Bean才会被视为配置文件(@Configuration)解析 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<>(result); }
条件过滤是有顺序:(追究这个好像没什么意义,最终Condition都生效了......)
1、先select过滤:在调用AutoConfigurationImportSelector.filters时仅仅只检测@ConditionOnClass @ConditionOnBean @ConditionOnWebApplication三个条件
2、后class上的@Condition过滤:这个时候类上的@ConditionalOnProperty才会生效
以AopAutoConfiguration为例
@Configuration @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,AnnotatedElement.class }) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { ... }
将spring.aop.auto = false,依然扫描进了configurations中,后续类加载时,@ConditionOnProperty才生效
三、总结
1、springboot主动注解配置,是依赖spring源码中BeanFactory的后置处理器ConfigurationClassPostProcessor实现的,这个后置处理器是在ApplicationContext的构造方法中注入到IOC容器中的,ConfigurationClassPostProcessor会处理解析5个注解@Configuration、@Import、@ImportResource、@Component、@ComponentScan。
2、@SpringBootApplication = @Configuration+@ComponentScan+@Import(AutoConfigurationImportSelector.class) +@Import(AutoConfigurationPackages.Registrar.class)
- @Configuration:主要是一个属性proxyBeanMethods:默认开启(true),允许其他类调用@Bean注解的方法,为false的话,不允许则想要一个@Bean注解的类型只能自己初始化一个。
- @ComponentScan:springboot扫描MainClass所在包下的class文件。这个标签basePackages、basePackageClasses未指定时,扫描注解类(MainClass)所在package下的所有class文件到IOC容器中。
- @Import(AutoConfigurationImportSelector.class):自动配置的核心。会调用selector.selectImports(medata)方法,获取/META-INF/spring.factories文件中的EnableAutoConfiguration映射的class数组,class数组就是配置类的集合。(可视为每个类被@Configuration注解)。
- @Import(AutoConfigurationPackages.Registrar.class):注册basePackage为一个BeanDefinition到容器中。注意仅仅是记录basePackage,不会进行包扫描,包扫描由上面的@ComponentScan实现
3、springboot的SPI机制:对应文件/META-INF/spring.factories,所有的自动发现并加载的类都配置在这里面。这也是springboot热拔插的原因,直接依赖jar包,就可以使用redis,kafka等中间件,通过spring.factories+@ConditionOnClass(判断Class是否存在 == 是否引入jar包)来发现中间件的Bean,例如RedisTemplate等
4、spring的启动顺序:
① initalizers+listeners+webType
② 异常记录器exceptionReporters +headless模式
③ 初始化环境变量environment(命令行参数+spring.profiles.active+系统环境变量path)
④ printbanner日志横幅
⑤ 根据webType创建对应的容器ApplicationContext,
⑥ initalizers+listeners+environment与容器ApplicationContext的互相绑定
⑦ 容器启动(允许自定义scope,重写AbstarctApplicationContext的onRefresh,开启tomcat服务)
四、遗留问题
1、知道了怎么找到配置类,但是属性自动注入还没有弄清楚
2、知道tomcat启动的地方,但嵌入细节不知道,开启一个后台线程吗?
五、补充
1、SpringBoot自定义的注解@ConditionOnClass等