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等

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM