springboot的自动装配原理初探

面试时经常被hr问到的问题!!!学会后立马+K

原理初探

自动配置:

pom.xml

  • spring-boot-dependencies:核心依赖在父工程中!
    在这里插入图片描述
    在这里插入图片描述

  • 点击进去就会看到很多版本,我们在写或者引入一些Springboot依赖的时候,不需要指定版本,就是因为有这些版本仓库。
    在这里插入图片描述

启动器:

	<dependency>
	            <groupId>org.springframework.boot</groupId>
	            <artifactId>spring-boot-starter-web</artifactId>
	        </dependency>
  • 启动器:说白了就是Springboot的启动场;
  • 比如spring-boot-starter-web,他就会帮我们自动导入web环境所有的依赖!
  • Springboot会将所有的功能场景,都变成一个个事务启动器
  • 我们要使用什么功能,就只需要找到对应的启动器可以了 starter

主程序:

//程序主入口
//SpringBootApplication:标注这个类是一个Springboot的应用:启动类下的所有被导入的资源
@SpringBootApplication
public class HelloApplication {

    public static void main(String[] args) {
        //SpringApplication     将Springboot应用启动
        SpringApplication.run(HelloApplication.class, args);
    }

}

@SpringBootApplication

但是一个简单的启动类并不简单!我们来分析一下这些注解都干了什么

  1. @SpringBootApplication
    意义:SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpingBoot应用;

    进入这个注解:可以看到上面还有很多其他注解!

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    
  2. @ComponentScan
    这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能就是自动扫描并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中;

  3. @SpringBootConfiguratian
    意义:SpringBoot的配置类:标注在某个类上,表示这是一个SpringBoot的配置类;

    我们继续进去这个注解查看

    @Configuration	//点进去得到下面的  @component
    public @interface SpringBootConfiguration {
        @AliasFor(
            annotation = Configuration.class
        )
        boolean proxyBeanMethods() default true;
    }
    
    

    @Configutation: 配置类上来标注这个注解,说明这是一个配置类,配置类…即…配置文件:

    我们继续点进去,发现配置类也是容器中的一个相件,@Camponent,这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!

  4. @EnableAutoConfiguration
    我们回到SpringBootApplication注解中继续看。
    在这里插入图片描述
    @EnableAutaconfiguration:开启自动配置功能

    以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置;

    @EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

    我们点击去查看。发现注解@AutoConfiguration Package:自动配置包

    @AutoConfigurationPackage	//自动配置包
    @Import(AutoConfigurationImportSelector.class)		//导入哪些组件的选择器
    public @interface EnableAutoConfiguration {
    }
    

    再点进去看到一个@Import({Registrar.class))

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

    @import: Spring底层注解@import,给容器中导入一个组件

    Registrar.class 将主配置类【即@SpringBootApplication标注的类】的所在包及包下面所有子包里面的所有组件扫描到Spring容器:

    退到上一步, 继续看:@Import(Autoconfigurationlmportselector.clas):给容器导入组件;

    AutoConfigurationlmportSelector: 自动配置导入选择器,那么它会导入哪些组件的选择器呢?

    1. 这个类中有一个这样的方法

      //获得候选的配置
      protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
      		//这里的getSpringFactoriesLoaderFactoryClass()方法
      		//返回的就是我们最开始的启动自动导入配置文件的注解类EnableAutaconfiguration
      		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;
      	}
      
    2. 这个方法又调用了SpringFactoriesLoader类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames()方法

          public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
              String factoryTypeName = factoryType.getName();
              //这里它又调用了loadSpringFactories方法
              return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
          }
      
    3. 我们继续点击查看loadSpringFactories方法

          private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
              //获得classloader			我们返回可以看到这里得到的就是EnableAutaconfiguration标注的类本代码
              MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
              if (result != null) {
                  return result;
              } else {
                  try {
                  	//去获取一个资源"META-INF/spring.factories"
                      Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                      LinkedMultiValueMap result = new LinkedMultiValueMap();
      
                      while(urls.hasMoreElements()) {
                          URL url = (URL)urls.nextElement();
                          UrlResource resource = new UrlResource(url);
                          Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                          Iterator var6 = properties.entrySet().iterator();
      
                          while(var6.hasNext()) {
                              Entry<?, ?> entry = (Entry)var6.next();
                              String factoryTypeName = ((String)entry.getKey()).trim();
                              String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                              int var10 = var9.length;
      
    4. 我们根据源头打开springfactories前配置文件,看到了很多自动配置的文件;这就是自动配置的根源所在!
      在这里插入图片描述
      WebMvcAutoConfiguration

      我们在上面的自动配置类随便找一个打开看看,比如:WebMvcAutoConfiguration
      在这里插入图片描述
      可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

    所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中对应的org-springframework.boot.autoconfigure.包下的配置项,通过反射实例化为
    对应标注了@Configuration的Javaconfig形式的IOC容器配置类,然后将这些都汇总成为一个实例并加载到IOC容器中。

结论:

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器,自动配置类就生效,帮我们进行自动配置工作;
  3. 以前我们需要自己配置的东西,自动配置类都帮我们解决了
  4. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  5. 它将所有需要导入的组件以全类名的方式返回,这些组体就会被添加到容器中;
  6. 它会给容器中导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件;
  7. 有了自动配置类,兔去了我们手动编写配置注入功能组件等的工作;
  • 注解

    @SpringBootConfiguration	springboot的配置
    	@Configuration		spring配置类
    		@Component		说明这也是一个spring的组件
    
    @EnableAutoConfiguration		自动配置
    	@AutoConfigurationPackage		自动配置包
    		@Import(AutoConfigurationPackages.Registrar.class)		自动配置‘包注册’
    	@Import(AutoConfigurationImportSelector.class)		自动配置导入选择
    		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);		获取所有的配置
    
    

获取候选的配置

	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;
	}

META-INF/spring.factories :自动配置的核心文件

Properties properties = PropertiesLoaderUtils.loadProperties(resource);
所有的资源加载到配置类中

Run

我最初以为就是运行了一个main方法,没想到却开启了一个服务;

@SpringBootApplication
public class HelloApplication {

    public static void main(String[] args) {
        //SpringApplication     将Springboot应用启动
        //run方法
        //这里返回一个ConfigurationApplicationContext对象
        //参数一:应用入口的类        参数类:命令行参数
        SpringApplication.run(HelloApplication.class, args);
    }

}

SpringApplication.run分析

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication

这个类主要做了以下四件事情

  1. 推断应用的类型是普通的项目还是Web项目
  2. 查找并加载所有可用初始化器,设置到initializers属性中
  3. 找出所有的应用程序监听器,设置到listeners属性中
  4. 推断并设置main方法的定义类,找到运行的主类

点进去可查看构造器
在这里插入图片描述
在这里插入图片描述

这几个原理在面试时特别经常被问到!!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值