zoukankan      html  css  js  c++  java
  • 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等

  • 相关阅读:
    循环图片 yi
    给大家一个经典的.net情感故事 yi
    [东邪西毒][程序员版][原版][剧情] yi
    Sqlite 使用笔记 中文显示为乱码 yi
    sql2005安装过程,(不装C盘) yi
    Visual Studio 2010 美女与程序员的爱情网剧全集 yi
    IT行业几大职业病 yi
    标准化操作
    【ActiveMQ Tuning】Serializing to Disk
    我的山寨敏捷四季之春
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12552114.html
Copyright © 2011-2022 走看看