写点什么

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

  • 2023-07-03
    福建
  • 本文字数:3152 字

    阅读完需:约 10 分钟

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 内置了很多条件注解,如下表所示:



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



以 @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
* <b>not</b> 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.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 用户在写配置文件时,会有提示效果 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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 测试自动配置是否生效


@SpringBootTestpublic 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());
}
}
复制代码


相关内容拓展:(技术前沿)

近 10 年间,甚至连传统企业都开始大面积数字化时,我们发现开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。


针对这类问题,低代码把某些重复出现的场景、流程,具象化成一个个组件、api、数据库接口,避免了重复造轮子。极大的提高了程序员的生产效率。


推荐一款程序员都应该知道的软件 JNPF 快速开发平台,采用业内领先的 SpringBoot 微服务架构、支持 SpringCloud 模式,完善了平台的扩增基础,满足了系统快速开发、灵活拓展、无缝集成和高性能应用等综合能力;采用前后端分离模式,前端和后端的开发人员可分工合作负责不同板块,省事又便捷。


免费体验官网:www.jnpfsoft.com/?infoq

还没有了解低代码这项技术可以赶紧体验学习!

发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot——自定义自动配置与起步依赖_spring_互联网工科生_InfoQ写作社区