SpringBoot原理讲解

一.问题的引入

首先咱们来看一个最简单的例子。java

咱们先建立一个SpringBoot的工程,如何建立一个SpringBoot工程就不说了,不会请自行解决。而后写一个controller类,经过请求路径,返回HelloWorld在浏览器页面上显示。程序员

        

  上面两张图就是程序的一个总体的结构和运行的结果,那么问题来了,SpringBoot程序中没有任何配置,不像Spring框架,写一大堆配置信息在xml文件中,那么程序是怎么将咱们这里的Controller类扫描到spring容器中的呢?spring

二.原理讲解。

首先第一点,咱们来看一下SpringBoot的启动类,浏览器

package com.example.demo;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;



@SpringBootApplication

public class DemoApplication {



    public static void main(String[] args) {

        //启动SpringBoot应用

        SpringApplication.run(DemoApplication.class, args);

    }

}

  

其中,咱们看到一个注解@SpringBootApplication,SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;框架

而后咱们点进去看看这个注解到底包含了什么,ide

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

public @interface SpringBootApplication {      

  

其中咱们须要重点关注的就是@SpringBootConfiguration、@EnableAutoConfiguration学习

下面咱们逐个来说解:url

@SpringBootConfiguration这个注解顾名思义,标注在某个类上,这个类就是SpringBoot的配置类,咱们再点进去看看。debug

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration

  

 

原来这个注解是底层是Spring中的注解@Configuration,而@Configuration注解底层就是一个@Component,表明一个容器。xml

 

 

SpringBoot的精髓是在@EnableAutoConfiguration这个注解上,根据名字,咱们能够知道这是一个自动配置类,也就是可以实现一些自动配置的功能,那么具体是配置了什么东西呢?

咱们再点进去看看

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

  

咱们看见了和这个注解有关联的重要的两个注解@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class),也是分别给你们讲解一下。

1.@AutoConfigurationPackage

@AutoConfigurationPackage:这是一个自动配置的包,咱们来看下在这个程序中是配置了哪一个包,点进来

@Import(AutoConfigurationPackages.Registrar.class)

  

 

再点到Register,咱们看到在大概123行的位置,有一段代码。

@Override

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

   register(registry, new PackageImport(metadata).getPackageName());

}

  

咱们看到这个方法器中一个参数metadata,表明注解的元信息,而后咱们经过这个注解的元信息来获这个包名,咱们在这打个断点,debug运行,能够看见一些元信息的基本内容,最主要咱们要知道是导入了哪一个包,咱们选中new PackageImport(metadata).getPackageName(),右键计算一下

发现导入的包就是咱们项目的根目录,假如咱们新建一个包叫com.controller,在里面写一个controller类,你们能够运行的试一下是否能成功呢。

 

2.@Import(AutoConfigurationImportSelector.class)

     @Import(AutoConfigurationImportSelector.class):这个注解表明的是一个自动配置的选择器,那么要导入哪些组件的选择器呢?

咱们点进去,看到很是重要的一段。

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

   configurations = filter(configurations, autoConfigurationMetadata);

   fireAutoConfigurationImportEvents(configurations, exclusions);

   return new AutoConfigurationEntry(configurations, exclusions);

}

  

 这里咱们得到到了一个configurations 的list集合,咱们打个断点看看这个集合中到底给咱们装了些什么东西。

咱们发现这个configurations 里面装配了124个自动配置类,原来咱们没有配置的一些信息,都经过SpringBoot的自动配置类给我配置好了。

那么我还想知道这些类SpringBoot程序给咱们放到哪了呢,咱们看到getCandidateConfigurations(annotationMetadata, attributes);

点进去,咱们看到:

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()

  

 

那么再点进去咱们看看到底加载的工厂名称是啥,

try {

   Enumeration<URL> urls = (classLoader != null ?

         classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :

         ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

   result = new LinkedMultiValueMap<>();

   while (urls.hasMoreElements()) {

      URL url = urls.nextElement();

      UrlResource resource = new UrlResource(url);

      Properties properties = PropertiesLoaderUtils.loadProperties(resource);

      for (Map.Entry<?, ?> entry : properties.entrySet()) {

         String factoryTypeName = ((String) entry.getKey()).trim();

         for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {

            result.add(factoryTypeName, factoryImplementationName.trim());

         }

      }

   }

  

咱们看到其中类加载器给咱们获取了资源,咱们点进去,

点了这么屡次,终于找到咱们想要的答案了!!!

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

  

 

原来这些自动配置类都在类路径下的"META-INF/spring.factories"

还有下面的autoconfigure包中的内容,咱们也看看

这里面咱们全部所用到的配置类所有由SpringBoot给咱们配置了,因此咱们知道SpringBoot表面上是零配置的,其实底层都给咱们封装好了,也是方便咱们程序员进行开发。

那么有些人确定又有疑惑,SpringBoot怎么知道给咱们自动配置哪些类呢?

欲知后事如何,请关注一下做者,纯手打码字不易,也是但愿和你们多多交流,一块儿学习,谢谢!

相关文章
相关标签/搜索