• SpringBoot——自定义自动配置与起步依赖


    SpringBoot——自定义自动配置与起步依赖

    SpringBoot为我们提供了灵活强大的自动配置与起步依赖功能,接下来我们参考其实现原理,实现专属于我们自己的自动配置与起步依赖。
    不仅如此,我们对其稍作修改,让它适用于非SpringBoot环境,甚至是低版本的Spring Framework环境

    1自动配置

    在编写自己的自动配置之前,我们先来看一下SpringBoot自动配置类的实现原理。

    SpringBoot可以根据CLASSPATH、配置项等条件自动进行常规配置,省去了我们自己手动把一模一样的配置复制来复制去的麻烦。这样大大提升了开发效率!
    在这之前,我们已经看到过@SpringBootApplication注解了,查看这个注解,可以发现它上面添加了一个@EnableAutoConfiguration,基于这个注解就可以开启自动配置功能。
    这两个注解上都有exclude属性,我们可以在其中排除一些不想启用的自动配置类。
    如果不想启用自动配置功能,也可以在配置文件中配置spring.boot.enableautoconfiguration=false,关闭该功能。

    1.1自动配置的实现原理

    自动配置类其实就是添加了@Configuration的普通Java配置类,它利用Spring Framework 4.0加入的条件注解@Conditional来实现“根据特定条件启用相关配置类”,注解中传入的Condition类就是不同条件的判断逻辑。SpringBoot内置了很多条件注解,如下表所示:

    条件注解 生效条件
    @ConditionalOnBean 存在特定名称、特定类型、特定泛型参数或带有特定注解的Bean
    @ConditionalOnMissingBean 与前者相反,不存在特定的Bean
    @ConditionalOnClass 存在特定的类
    @ConditionalOnMissingClass 与前者相反,不存在特定类
    @ConditionalOnCloudPlatform 运行在特定的云平台上,截止2.6.3版本,代表云平台的枚举类支持无云平台,可以通过spring.main.cloud-platform配置强制使用的云平台
    @ConditionalOnExpression 指定的SpEL表达式为真
    @ConditionalOnJava 运行在满足条件的Java上,可以比指定版本新,也可以比指定版本旧
    @ConditionalOnJndi 指定的JNDI位置必须存在一个,如没有指定,则需要存在InitalContext
    @ConditionalOnProperty 属性值满足特定条件,比如给定的属性值都不能为false
    @ConditionalOnResource 存在特定资源
    @ConditionalOnSingleCandidate 当前上下文中,特定类型的Bean有且仅有一个
    @ConditionalOnWarDeployment 应用程序是通过传统的War方式部署的,而非内嵌容器
    @ConditionalOnWebApplication 应用程序是一个Web应用程序
    @ConditionalOnNotWebApplication 与前者相反,应用程序不是一个Web应用程序

    👇更多如图所示,就不一一列举了:
    image

    以@ConditionalOnClass注解为例,它的定义如下所示,@Target指明该注解可用于类型和方法定义,@Retention指明注解的信息在运行时也能获取到,而其中最关键的就是OnClassCondition条件类,里面是具体的条件计算逻辑:

    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(OnClassCondition.class)
    public @interface ConditionalOnClass {
    /**
    * The classes that must be present. Since this annotation is parsed by loading class
    * bytecode, it is safe to specify classes here that may ultimately not be on the
    * classpath, only if this annotation is directly on the affected component and
    * not if this annotation is used as a composed, meta-annotation. In order to
    * use this annotation as a meta-annotation, only use the {@link #name} attribute.
    * @return the classes that must be present
    */
    Class[] value() default {};
    /**
    * The classes names that must be present.
    * @return the class names that must be present.
    */
    String[] name() default {};
    }

    了解了条件注解后,再来看看它们是如何与配置类结合使用的。以JdbcTemplateAutoConfiguration为例:

    @AutoConfiguration(after = DataSourceAutoConfiguration.class)
    @ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
    @ConditionalOnSingleCandidate(DataSource.class)
    @EnableConfigurationProperties(JdbcProperties.class)
    @Import({ DatabaseInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,
    NamedParameterJdbcTemplateConfiguration.class })
    public class JdbcTemplateAutoConfiguration {
    }

    可以看到这个配置类的生效条件是存在DataSource和JdbcTemplate类,且在上下文中只能有一个DataSource。此外,这个自动配置需要在DataSourceAutoConfiguration之后再配置(可以用@AutoConfigureBefore、@AutoConfigureAfter和@AutoConfigureOrder来控制自动配置的顺序)

    2编写自已的自动配置

    根据上面的描述,我们很容易想到,要编写自己的自动配置,只需要以下三个步骤:
    (1)编写常规的配置类
    (2)为配置类增加生效条件与顺序
    (3)在/META-INF/spring.factories文件中添加自动配置类

    2.1创建项目

    在Spring Initializr中,创建一个Maven工程,添加如下依赖:

    <dependencies>
    <dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-autoconfigureartifactId>
    dependency>
    <dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-configuration-processorartifactId>
    dependency>
    <dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <optional>trueoptional>
    dependency>
    <dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-testartifactId>
    <scope>testscope>
    dependency>
    dependencies>

    2.2编写一个简单的MyAutoConfigure类和配置类Bean

    编写一个简单的MyAutoConfigure类,上面增加了@Configuration注解,表示这是一个配置类,这个配置类的生效条件是myconfig.ready属性的值为true,除此之外的值或者不存在该属性时MyAutoConfigure都不会生效。

    /**
    * TODO 1、编写配置类并指定文件
    *
    * @author ss_419
    * @version 1.0
    * @date 2023/3/17 21:24
    */
    @Configuration
    @EnableConfigurationProperties(CommonBean.class)
    @ConditionalOnProperty(name = "myconfig.ready",havingValue = "true")
    public class MyAutoConfigure {
    }
    /**
    * TODO 2、创建配置类Bean
    *
    * @author ss_419
    * @version 1.0
    * @date 2023/3/17 22:40
    */
    @ConfigurationProperties("myconfigbean")
    @Data
    public class MyConfigBean {
    private boolean ready;
    private String info;
    }

    2.3配置spring.factories文件

    为了让SpringBoot能找到我们写的这个配置类,我们需要在src/resources目录中创建META-INF/spring.factories文件,其内容如下:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.pp.myspringbootstart.beans.MyAutoConfigure

    2.4测试自动配置是否生效

    @SpringBootTest
    public class MyConfigurationEnableTest {
    @Autowired
    private ApplicationContext applicationContext;
    @Test
    void testPropertiesBeanAvailableTest() throws Exception {
    assertNotNull(applicationContext.getBean(MyConfigBean.class));
    assertTrue(applicationContext.containsBean("org.pp.myspringbootstart.beans.MyConfigBean"));
    }
    @Test
    void testPropertyValues(){
    MyConfigBean bean = applicationContext.getBean(MyConfigBean.class);
    assertTrue(bean.isReady());
    assertEquals("hello", bean.getInfo());
    }
    }
  • 相关阅读:
    09-排序3 Insertion or Heap Sort(浙大数据结构)
    根据 Excel 列生成 SQL
    AVL树你需要了解一下
    使用位运算技巧实现加减乘除
    设计模式之责任链模式
    小波神经网络的基本原理,小波神经网络功能分析
    【精】Devops实战学习CI/CD落地方案#CI篇#
    1,2,4,5-四嗪-巯基反应Methyltetrazine-Maleimide/PEG2-maleimide/PEG5-Maleimide的制备
    Proteus中如何使用Arduino实现 ST7735显示屏十六宫格拼图游戏
    Ubuntu——卸载、安装CUDA
  • 原文地址:https://www.cnblogs.com/atwood-pan/p/17228628.html