SpringBoot之启动@SpringBootApplication原理分析

1、SpringBoot 启动main()

1 @SpringBootApplication
2 public class TomcatdebugApplication {
3 
4     public static void main(String[] args) {
5         SpringApplication.run(TomcatdebugApplication.class, args);
6     }
7 
8 }

1.1  @SpringBootApplication 注解,其实主要是 @ComponentScan@EnableAutoConfiguration@SpringBootConfiguration 三个注解

 

 

  @ComponentScan 注解:

      spring里有四大注解:@Service,@Repository,@Component,@Controller用来定义一个bean.@ComponentScan注解就是用来自动扫描被这些注解标识的类,最终生成ioc容器里的bean.

     可以通过设置@ComponentScan basePackages,includeFilters,excludeFilters属性来动态确定自动扫描范围,类型已经不扫描的类型.

  默认情况下:它扫描所有类型,并且扫描范围是@ComponentScan注解所在配置类包及子包的类

 

@SpringBootConfiguration 注解:

      

@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类,
并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。

 demo 说明:

(1) 注入spring ioc bean

 1 @SpringBootConfiguration
 2 public class Config {
 3     @Bean
 4     public Map createMap(){
 5         Map map = new HashMap();
 6         map.put("username","gxz");
 7         map.put("age",27);
 8         return map;
 9     }
10 }

(2)调用:

public static void main( String[] args )
    {
        //方式1 获取context
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
        context.getBean(Runnable.class).run();
        context.getBean("createMap");   //注意这里直接获取到这个方法bean
        int age = (int) map.get("age");
        System.out.println("age=="+age);

//方式2. 使用@Autowired注解,应用bean 
// @Autowired
// Map
createMap
}

 

@EnableAutoConfiguration 注解

      @EnableAutoConfiguration作用:从classpath中搜索所有的META-INF/spring.factories配置文件,然后将其中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的value加载到spring容器中。

     

 

上图分析源码可知: @EnableAutoConfiguration = @Import + @AutoConfigurationPackage

@AutoConfigurationPackage: 主要作用是自动配置包

@Import: Spring底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class 将主配置类(@SpringBootApplication标注的类)的所在包以及下面所有子包里面的所有组件扫描到Spring容器。

       AutoConfigurationImportSelector的作用是导入哪些组件的选择器。将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中;也会给容器导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件。
  有了自动配置类,免去了我们手动编写配置注入功能组件等的工作

  

具体工作流程图:

 

 

 

@EnableAutoConfiguration加载过程 

 自动配置主要由AutoConfigurationImportSelector实现的,我们主要从这个类开始讲起。AutoConfigurationImportSelector是@EnableAutoConfiguration“@Import”的DeferredImportSelector实现类,由于DeferredImportSelector作为ImportSelector的子接口,所以组件自动配置逻辑均在selectImports(AnnotationMetadata)方法中实现

源码分析:

  

AutoConfigurationImportSelector.java

根据以上代码分析自动配置加载过程主要分为以下几个步骤:

  • 1.判断是否开启自动配置
  • 2.从META-INF/spring-autoconfigure-metadata.properties文件中载入属性配置
  • 3.获取所有的配置列表
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    //1.是否开启自动配置,默认开启
    if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
        //2.从META-INF/spring-autoconfigure-metadata.properties文件中载入属性配置(有一些有默认值),获取注解信息

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);

       
       //3.获取所有的配置列表
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return (String[])configurations.toArray(new String[configurations.size()]);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}


1.是否开启自动配置,默认开启

  protected boolean isEnabled(AnnotationMetadata metadata) {
        return true;
    }

2.从META-INF/spring-autoconfigure-metadata.properties文件中载入属性配置

 protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";

    private AutoConfigurationMetadataLoader() {
    }

    public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }

    static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
        try {
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources(path) : ClassLoader.getSystemResources(path);
            Properties properties = new Properties();

            while(urls.hasMoreElements()) {
                properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource((URL)urls.nextElement())));
            }

            return loadMetadata(properties);
        } catch (IOException var4) {
            throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", var4);
        }
    }

3、获取所有的配置列表

  protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
        String name = this.getAnnotationClass().getName();
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
        Assert.notNull(attributes, "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?");
        return attributes;
    }

总结:

 springboot底层实现自动配置的步骤:

  • 1.springboot应用启动
  • 2.@SpringBootApplication起作用
  • 3.@EnableAutoConfiguration
  • 4.@AutoConfigurationPackage:这个组合注解主要是@Import(AutoConfigurationPackages.Registrar.class),它通过将Registrar类导入到容器中,而Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到springboot创建管理的容器中
  • 5.@Import(AutoConfigurationImportSelector.class):它通过将AutoConfigurationImportSelector类导入到容器中,AutoConfigurationImportSelector类作用是通过selectImports方法实现将配置类信息交给SpringFactory加载器进行一系列的容器创建过程,具体实现可查看上面的源码

猜你喜欢

转载自www.cnblogs.com/123-shen/p/SpringBoot.html