4

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

 1 year ago
source link: https://www.cnblogs.com/atwood-pan/p/17228628.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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 * <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")@Datapublic 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()); }}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK