springboot的自动配置
编写自定义starter之前,先来简要介绍下springboot的自动配置的相关特征。
spring-boot-autoconfigure 依赖
spring-boot-autoconfigure 依赖,是Spring Boot实现自动配置的核心Starter组件,它的工作原理很简单,通过@EnableAutoConfiguration
让SpringBoot根据类路径中的jar包依赖为当前项目进行自动配置,例如,添加了spring-boot-starter-web
依赖,会自动添加Tomcat和Spring MVC的依赖,那么Spring Boot会对Tomcat和Spring MVC进行自动配置
@EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@EnableAutoConfiguration注解通过@Import注解导入的配置功能,AutoConfigurationImportSelector利用SpringFactoriesLoader.loadFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包,将所有符合条件的自动配置类加载到IoC容器中,更多关于此注解的介绍请参阅之前的文章 :springboot系列文章之SpringBootApplication注解
@Conditional条件注解
在SpringBoot的自动配置中大量使用了条件注解,拿Spring AOP的自动配置类来说:
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
在这个类中就使用了@ConditionalOnClass
,@ConditionalOnProperty
等条件注解。这些条件注解都是组合了 @Conditional
这个元注解来的,只是使用了不同的条件(Condition)。
@Conditional
根据满足某一个特定条件创建一个特定的Bean,比如说,当某一个jar包在一个类路径下时,自动创建一个或者多个Bean。如果要自定义判断条件,我们就需要实现 Condition 接口,并重写其 matches 方法来构造判断条件
public class QiNiuYunCondition implements Condition {
private static Logger logger = LoggerFactory.getLogger(QiNiuYunCondition.class);
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String property = context.getEnvironment().getProperty("qiniuyun.accessKey");
if (StringUtils.isEmpty(property)) {
throw new RuntimeException("没有七牛云的配置");
} else {
return true;
}
}
}
@Configuration
@Conditional(QiNiuYunCondition.class)
public class QiNiuYunServiceAutoConfiguration {
....
}
有很多基于@Conditional
的组合注解常常用于自动配置中,比如:
- @ConditionalOnBean(仅仅在当前容器中存在某个对象时,才会实例化一个Bean)
- @ConditionalOnClass(当容器中某个class位于类路径上,才会实例化一个Bean)
- @ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
- @ConditionalOnMissingBean(仅仅在当前容器中不存在某个对象时,才会实例化一个Bean,容器不能实例化两次)
- @ConditionalOnMissingCla