• RTFSC:SpringBoot 源码惊鸿一瞥


    1、从主方法入手

    SpringBoot应用常规的main方法如下:

    @SpringBootApplication
    public class SpringBootDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringBootDemoApplication.class, args);
        }
    }
    

    可以看到一个灵魂注解@SpringBootApplication , 按住ctrl点进去看:

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
        ....
        ....
    }
    

    注意到它是一个组合注解,三个大件@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan

    2、注解:@SpringBootConfiguration

    @SpringBootConfiguration入手,按住ctrl追进去,发现:

    @Configuration
    public @interface SpringBootConfiguration {
        .....
    }
    

    它其实就是一个@Configuration 注解,它标注在哪个类上,就表示当前类是一个配置类。

    既然这样,那可以理解这个注解被包装又包装后标注在了SpringBootDemoApplication类上,也就是说Main方法所在的类也是一个配置类。

    3、注解:@ComponentScan

    这个注解非常简单,就是指定要扫描哪些包,按需调整使用。不多说~

    4、注解:@EnableAutoConfiguration

    按住ctrl点进去看:

    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
        ....
    }
    

    可以发现它又是个组合注解,翻译一下:

    • @AutoConfigurationPackage : 自动配置包;
    • @Import(AutoConfigurationImportSelector.class) : 导入这么个类,说人话就是把这个类放入IOC容器中。

    4.1 注解:@AutoConfigurationPackage

    ctrl进入源码一探究竟:

    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
           ....
    }
    

    它其实就是一个@import注解, 而import的含义就是给容器中导入一个组件。它给容器中导入了一个Registrar,这又是个啥?点进去,看它!!!

    	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
    		@Override
    		public void registerBeanDefinitions(AnnotationMetadata metadata, 			BeanDefinitionRegistry registry) {
    			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
    		}
    
    		@Override
    		public Set<Object> determineImports(AnnotationMetadata metadata) {
    			return Collections.singleton(new PackageImports(metadata));
    		}
    
    	}
    

    发现它有两个方法,其实也就是Registrar在利用registerBeanDefinitions方法在向容器中国批量注入组件。到底在批量注册什么呢,断点打在register方法处,走起~

    这个方法传入了两个参数,其中有一个是AnnotationMetadata metadata, 叫做注解的元信息

    这个注解指的是@AutoConfigurationPackage , 可以看到注解的元信息包括如下内容。其中有一条表示该注解标在了哪个类上——其实就是启动程序所在的类。

    回头看register方法,单独计算其中的入参new PackageImports(metadata).getPackageNames(),得到这个结果,得到了一个包名,很明显这个包就是启动程序所在的包

    为什么是这个包名?因为@AutoConfigurationPackage 实际上就是标注在启动程序所在的类,那么根据注解元信息获取到的包名自然就是这个类所在的包。

    总结:到这基本上就清楚了,@AutoConfigurationPackage 就是根据包名,将这个包下的所有组件批量注册进容器。(此处所说包名,即为启动程序所在的包名)这也就解释了默认的包扫描路径是启动程序所在的包

    4.2 @Import(AutoConfigurationImportSelector.class)

    @Import利用Selector机制给容器中批量导入组件,进入AutoConfigurationImportSelector,找到一个方法selectImports:

    // 到底要导入哪些?这个数组中规定要导入哪些就导哪些
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS;
    		}
        
    		AutoConfigurationEntry autoConfigurationEntry 
                // 所有的东西都是由这个方法得到的,重点看这个方法:
                = getAutoConfigurationEntry(annotationMetadata);
        
        	// 根据上边方法得到的结果,封装返回值
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    

    断点打在 getAutoConfigurationEntry(annotationMetadata)(字面意思:获取所有自动配置的集合)处,Debug模式运行:

    getCandidateConfigurations(annotationMetadata, attributes)执行后得到一个configurations集合,接着对这个数组做了多个操作,然后封装返回结果。

    该方法执行后得到所有候选的配置类,一共是127个(SpringBoot版本是2.3.4.RELEASE)。也就是说SpringBoot应用启动之初默认导入127个配置类。

    问题来了,导入规则依据什么? 进入``getCandidateConfigurations`方法一窥究竟。

    利用Spring工厂加载器加载一些东西,点进去看。

    拨开云雾见青天了,从META-INF/spring.factories位置来加载一个文件。

    • 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    • 最核心的spring-boot-autoconfigure-2.3.4.RELEASE.jar包有META-INF/spring.factories

    挖到祖坟了,不信你数,正好127个!!~~~ 撒花!!!

    总结:SpringBoot一启动就要给容器加载所有的配置类就在spring-boot-autoconfigure-2.3.4.RELEASE.jar包有META-INF/spring.factories。这里有个问题,要加载这么多组件,而实际上容器里并不会有那么多的组件。其中哪些可以生效,哪些不生效,就是接下来要聊的:按需开启自动配置项。

    4.3 按需开启自动配置项

    虽然SpringBoot在启动的时候会默认加载127个场景的自动配置,但是究竟有哪些生效按照条件装配规则(@Conditional),最终会按需配置。

    例如org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

    @Configuration(proxyBeanMethods = false)
    // 按照规则:配置文件中有前缀spring.aop auto 的配置项
    // havingValue = "true" 表示即便没配,默认为 true
    @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
    // 按照上述规则,这个配置类是生效的!
    public class AopAutoConfiguration {
    
    	@Configuration(proxyBeanMethods = false)
        //当容器中有Advice这个类的时候,这个类才会生效。 下边同理·~~
    	@ConditionalOnClass(Advice.class)
    	static class AspectJAutoProxyingConfiguration {
    		@Configuration(proxyBeanMethods = false)
    		@EnableAspectJAutoProxy(proxyTargetClass = false)
    		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
    				matchIfMissing = false)
    		static class JdkDynamicAutoProxyConfiguration {
    		}
            
    		@Configuration(proxyBeanMethods = false)
    		@EnableAspectJAutoProxy(proxyTargetClass = true)
    		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
    				matchIfMissing = true)
    		static class CglibAutoProxyConfiguration {
    		}}
        
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
    	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
    			matchIfMissing = true)
    	static class ClassProxyingConfiguration {
    	}
    }
    
  • 相关阅读:
    微信小程序学习之路 做一个捡金币的小游戏
    微信小程序 漂亮的按钮 多颜色+动态效果,超好看的button 样式
    hbase 工具
    Sass 在实际使用中的烦人点
    动态代理
    mutex_lock 函数分析
    Java OkHttpClient 模拟form表单提交数据&多文件
    wireshark抓包笔记
    开发qq小程序是一种什么体验
    Vue + Element UI (table) 合并行
  • 原文地址:https://www.cnblogs.com/simon-1024/p/14213796.html
Copyright © 2020-2023  润新知