美文网首页Java 杂谈程序员开源框架-SpringBoot系列
Springboot项目中 如何获取@Configuration

Springboot项目中 如何获取@Configuration

作者: Drew_Zhong | 来源:发表于2018-07-04 20:20 被阅读32次
    • 整个springboot并没有在spring的基础上提供什么额外的功能。

      从开发人员的角度来看,springBoot的最大作用就是引入某些jar包后,自动为spring上下文环境生成某些特定功能的Bean,这样就可以自动提供某些相关功能。

    • 从实现的角度来看,spring通过被标记了@Configuration的类提供一些提前生成好的Bean提供特别的功能,而用@Contional系列的注解限制生成的条件,通常就是@ConditionalOnClass和@ConditionalOnMissingBean注解的配合使用。前者确定某些功能需要的class已经有了,后者确定你没有自己生成相关的bean,才提供默认的。

    • 可以使用@AutoConfigureBefore,@AutoConfigureAfter,@AutoconfigureOrder 来确定某个自动注册类的生效顺序。作用类比@Order。

    • 自动注册一般提供2个module:一个是autoconfigure jar包,一个是starter jar包。其中starter这种jar里面并没有代码,是空的。唯一的作用是将需要的各种jar写入构建文件,这样引入此starter,就不要再去关心相应的其他jar了。

      springboot自己的starter实现是这么干的。

      SpringCloudNetflixZuul是将这两者统一于一个module中来实现的

    主要分成以下三个场景:

    1. @Configuration配置类在程序可以扫描到的package里,也就是@ComponentScan注解所指定的package里。SpringBoot工程天然支持该类配置类注入方式。

      最佳实践:

      最佳实践
      //@SpringBootApplication注解中含有@ComponentScan
      1 @SpringBootApplication
      2 public class Application {
      3     public static void main(String[] args) {
      4         SpringApplication.run(Application.class, args);
      5     }
      6 }
      
    2. @Configuration配置类没有在package扫描路径下,即不是项目开发人员自己编写的代码。

      比如制作第三方包供他人在springboot项目中使用,如RPC框架、starter工程、spring-cloud-netflix-zuul等。

      最佳实践:

      1、编写AutoConfiguration配置类

      2、在META-INF/spring.factories里用org.springframework.boot.autoconfigure.EnableAutoConfiguration来指定。

      spring-boot-autoconfigure包里的配置类都是通过这种方式引入的。

      示例:

      用于在项目中导入的第三方包spring-cloud-netflix-zuul

      image image

      引入spring-cloud-netflix-zuul的demo项目(实际是通过spring-cloud-starter-zuul引入的)

      当然,这个方式需要程序使用@EnableAutoConfiguration注解,这个注解是通过AutoConfigurationImportSelector来扫描spring.factories文件,把定义的配置类引入的。

    读取spring.factories文件的实现
    是通过org.springframework.core.io.support.SpringFactoriesLoader实现的。
    SpringFactoriesLoader的实现类似于SPI(Service Provider Interface)

    java SPI提供一种服务发现机制,为某个接口寻找服务实现的机制。

    有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

    实现说明:

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

    这是springboot项目中应用最常见的启动方式,核心有两个:

    • @SpringBootApplication注解
    • SpringApplication.run()静态方法

    和我们此处讨论有关系的是注解@SpringBootApplication

    @SpringBootApplication源码如下:

    @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 {....}
    

    @ComponentScan,spring的自动扫描注解,对应方法一。

    @EnableAutoConfiguration:借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器(建议放在根包路径下,这样可以扫描子包和类)

    @EnableAutoConfiguration源码如下:

    @SuppressWarnings("deprecation")
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {....}
    

    其核心是一个EnableAutoConfigurationImportSelector类

    public class EnableAutoConfigurationImportSelector
         extends AutoConfigurationImportSelector {...}
    

    核心方法在顶级接口ImportSelector的selectImports()的实现上,源码如下:

     @Override
     public String[] selectImports(AnnotationMetadata annotationMetadata) {
         if (!isEnabled(annotationMetadata)) {
             return NO_IMPORTS;
         }
         try {
              //1.从META-INF/spring-autoconfigure-metadata.properties文件中载入配置属性(有一些有默认值)
             AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                     .loadMetadata(this.beanClassLoader);
              //2.获取注解属性
             AnnotationAttributes attributes = getAttributes(annotationMetadata);
          //3.获取自动配置类    
              List<String> configurations = getCandidateConfigurations(annotationMetadata,
                     attributes);
              //4.移除重复的
             configurations = removeDuplicates(configurations);
              //5.排序
             configurations = sort(configurations, autoConfigurationMetadata);
              //6.排出需要排出的
             Set<String> exclusions = getExclusions(annotationMetadata, attributes);
             checkExcludedClasses(configurations, exclusions);
             configurations.removeAll(exclusions);
              //6.过滤器OnClassCondition(注解中配置存在某类才生效)
             configurations = filter(configurations, autoConfigurationMetadata);
              //7.触发自动配置导入监听事件
             fireAutoConfigurationImportEvents(configurations, exclusions);
             return configurations.toArray(new String[configurations.size()]);
         }
         catch (IOException ex) {
             throw new IllegalStateException(ex);
         }
     }
    
    1. 使用@Import注解

      这个注解可以引入三种类

      • 使用了@Configuration注解的类

        如spring-cloud-netflix中ZuulProxyAutoConfiguration通过@import导入了若干个被@Configuration注解的类

        image
      • ImportSelector的子类(严格说来这不属于被@Configuration标注的配置类这一前提,但也属于springboot自动配置能力的一种,故罗列在此)

        如@EnableAutoConfiguration中所引入的EnableAutoConfigurationImportSelector

        image
      • ImportBeanDefinitionRegistrar的子类

        {todo}

    初始spring boot

    spring boot容器启动详解

    相关文章

      网友评论

        本文标题:Springboot项目中 如何获取@Configuration

        本文链接:https://www.haomeiwen.com/subject/wluyuftx.html