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等

 

posted on 2020-03-23 14:42  FFStayF  阅读(4822)  评论(0编辑  收藏  举报