本专栏将从基础开始,循序渐进,以实战为线索,逐步深入SpringBoot相关知识相关知识,打造完整的云原生学习步骤,提升工程化编码能力和思维能力,写出高质量代码。希望大家都能够从中有所收获,也请大家多多支持。
专栏地址:SpringBoot专栏
本文涉及的代码都已放在gitee上:gitee地址
如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。
Spring Boot的核心功能就是为整合第三方框架提供自动配置,而本文则带着大家实现了自己的自动配置和Starter,一旦真正掌握了本文的内容,就会对Spring Boot产生“一览众山小”的感觉。
文章目录
自定义条件注解
在SpringBoot中,所有自定义条件注解其实都是基于@Conditional而来的,使用@Conditional定义新条件注解关键就是要有一个Condition实现类,该Condition实现类就负责条件注解的处理逻辑,该实现类所实现的matches()方法决定了条件注解的要求是否得到满足。
下面是自定义条件注解的Condition实现类的代码。
-
src/main/java/com/example/_003configtest/condition/MyCondition.java
package com.example._003configtest.condition;
import com.example._003configtest.annotation.ConditionalCustom;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;import java.util.Map;
public class MyCondition implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //获取@ConditionalCustom注解的全部属性,其中ConditionalCustom是自定义的注解 Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalCustom.class.getName()); //获取注解的value属性值 String[] vals = (String[]) annotationAttributes.get("value"); //env是application.properties或application.yml中配置的属性 Environment env = context.getEnvironment(); //遍历每个value的每个属性值 for (String val : vals) { //如果某个属性值对应的配置属性不存在,则返回false if(env.getProperty(val.toString())== null){ return false; } } return true; }
}
从上面的逻辑可以看到,自定义条件注解的处理逻辑比较简单:就是要求value属性所指定的所有配置属性必须存在,至于这些配置属性的值是什么无所谓,这些配置属性是否有值也无所谓。
有了上面的Condition实现类之后,接下来即可基于@Conditional来定义自定义条件注解。下面是自定义条件注解的代码。
-
src/main/java/com/example/_003configtest/annotation/ConditionalCustom.java
package com.example._003configtest.annotation;
import com.example._003configtest.condition.MyCondition;
import org.springframework.context.annotation.Conditional;import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//只要通过@Conditional指定Condition实现类即可,该Condition实现类就会负责该条件注解的判断逻辑
@Conditional(MyCondition.class)
public @interface ConditionalCustom {String[] value() default {};
}
下面的配置类示范了如何使用该自定义的条件注解:
-
src/main/java/com/example/_003configtest/config/MyConfigTest.java
// proxyBeanMethods = true :单例模式,保证每个@Bean方法被调用多少次返回的组件都是同一个
// proxyBeanMethods = false :原型模式,每个@Bean方法被调用多少次返回的组件都是新创建的
@Configuration(proxyBeanMethods = true)
public class MyConfigTest {
@Bean
//只有当applicaion.properties或application.yml中org.test1,org.test2两个配置属性都存在时才生效
@ConditionalCustom({“org.test1”,“org.test2”})
public MyBean myBean(){
return new MyBean();
}
}
在application.properties文件中添加如下配置:
org.test1 = 1
org.test2 = 2
运行测试发现成功获得了容器中对应的类:
自定义自动配置
开发自己的自动配置很简单,其实也就两步:
使用@Configuration和条件注解定义自动配置类。
在META-INF/spring.factories文件中注册自动配置类。
为了清楚地演示Spring Boot自动配置的效果,避免引入第三方框架导致的额外复杂度,本例先自行开发一个funny框架,该框架的功能是用文件或数据库保存程序的输出信息。
新建一个Maven项目funny(注意不是用SpringInitializr创建项目),为该项目添加mysql-connector-java和slf4j-api两个依赖。由于该项目是我们自己开发的框架,因此无须为该项目添加任何Spring Boot依赖。下面是该项目的pom.xml文件代码。
<?xml versio