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

370 阅读5分钟

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")

	@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());

	    }

	}

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

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

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

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

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

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