美文网首页springboot
用好springboot,离不开自动装载机制

用好springboot,离不开自动装载机制

作者: 求索 | 来源:发表于2020-03-03 13:08 被阅读0次

    springboot 比 spring 多了什么?

    现在springboot大行其道,很多面试官都会问,你觉得springboot对比spring有哪些不同?

    springboot 是用于整合spring体系越来越复杂的框架,其底层本身就是spring。其目的是为了让我们更好的使用spring框架。

    springboot 提供了非常多的start实现

    1. 能够快速创建基于Spring的应用程序;
    2. 能供直接使用java main 方法启动内置的Tomcat或者Jetty服务器运行...
    3. 提供约定的starter POM来简化Maven的配置,让Maven的配置变得更简单;
    4. 根据项目的Maven依赖配置,Spring Boot自动配置Spring、Spring ...
    5. 提供了程序的健康监控等功能;

    用springboot其目的是简化开发,提供开发效率。在框架搭建好,明确项目技术体系之后,日常开发我们就是在用spring,和直接基于spring的开发没有太多的区别。

    但是有些场景,比如redis在开发环境禁用,发布到线上希望启用;开发环境使用swagger,生产环境希望屏蔽;低层框架封装特定的Bean组件,在特殊子系统中希望覆盖该组件。解决诸如此类的问题,是springboot在日常工作中最常见的需求。自动装载机制就是用于解决这些问题的。

    自动装载机制原理介绍

    @EnableAutoConfiguration 将自动装载机制导入spring bean加载体系。

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

    注解 @Import 的代码注释

    Provides functionality equivalent to the {@code <import/>} element in Spring XML.

    该注解提供与Spring XML中的{@code<import/>}元素等效的功能。在这里我们导入了 AutoConfigurationImportSelector类。

    public class AutoConfigurationImportSelector
            implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
            BeanFactoryAware, EnvironmentAware, Ordered {
                //...
            }
    

    通过类接口我们可以看到他实现了DeferredImportSelector接口,该接口包含selectImports方法。selectImports方法是用于扫描bean加载的元数据信息的。

        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
                    autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    

    其中 getAutoConfigurationEntry 方法调用了fireAutoConfigurationImportEvents方法。fireAutoConfigurationImportEvents又调用了。

        protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
            return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
                    this.beanClassLoader);
        }
    

    SpringFactoriesLoader.loadFactories通过加载资源文件 META-INF/spring.factories加载元数据。

    自定义一个自动装载功能

    1. 实现一个类
      @Configuration 
      public class DemoAutoconfiguration {
          
          @Bean
          public Demo demo() {
              return new Demo();
          }
      }
      
    2. 在当前项目的资源文件中添加META-INF/spring.factories文件,并向其中添加刚才实现的类
      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
          cn.xxx.demo.autoconfigure.DemoAutoconfiguration,\
      

    满足上面两个条件,DemoAutoconfiguration里面定义的bean,就不需要在扫包就能直接使用了。当然DemoAutoconfiguration所在的jar,必须在你工程里面已经导入了。

    上面仅仅是一个简单的实现,springboot提供了很多实现自动装载的注解

    • ConditionalOnClass
    • ConditionalOnProperty
    • ConditionalOnMissingBean
    • ConditionalOnMissingClass

    如:

    @Configuration
    @EnableConfigurationProperties({DemoProperties.class})
    @ConditionalOnClass({DemoJarExists.class})
    @ConditionalOnProperty(name = "demo.enabled", havingValue = "true")
    @Slf4j
    public class DemoAutoconfiguration {
    
    }
    

    这个例子告诉bean加载时先判断DemoJarExists 类是否存在,如果不存在就跳过;同时要求配置项 demo.enabled =true 才能有效。

    设计理念

    自动装载机制通过META-INF/spring.factories 和 结果注解将可变性隔离,底层抽象出一套不可变的概念。任意的功能你都可以在自己的框架中重新覆盖实现,而且覆盖实现的成本仅仅是 实现一个Autoconfiguration。这大大提供了我们的研发效率,优化整体代码质量。

    分析源码是学习架构的非常好的手段,带着设计模式、架构理念去看源码,收获良多。

    相关文章

      网友评论

        本文标题:用好springboot,离不开自动装载机制

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