SpringBoot conditional注解和自定义conditional注解使用
发布日期:2021-06-30 18:59:32 浏览次数:2 分类:技术文章

本文共 5722 字,大约阅读时间需要 19 分钟。

conditional注解是Springboot starter的基石,自动装配的时候会根据条件确定是否需要注入这个类。

含义:基于条件的注解。

作用:根据是否满足某个特定条件来决定是否创建某个特定的Bean。

意义:Springboot实现自动配置的关键基础能力。

@ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean

@ConditionalOnClass:某个class位于类路径上才会实例化一个Bean
@ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean
@ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean
@ConditionalOnMissingClass:某个class不位于类路径上才会实例化一个Bean
@ConditionalOnNotWebApplication:不是web应用

 

配置文件有这个配置

spring.data.mongodb.uri=mongodb://paopaoedu:paopaoedu@localhost:27017/paopaoedu

判断有这个配置才注入这个类 

package com.paopaoedu.springboot.condition;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.stereotype.Component;@Component@ConditionalOnProperty("spring.data.mongodb.uri")public class ConditionalTest {}

 

测试文件

package com.paopaoedu.springboot;import com.paopaoedu.springboot.condition.ConditionalTest;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.BeansException;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTest(classes = {SpringBootLearningApplication.class})//不用类似new ClassPathXmlApplicationContext()的方式,从已有的spring上下文取得已实例化的bean。通过ApplicationContextAware接口进行实现。public class SpringBootLearningApplicationTests implements ApplicationContextAware {    private ApplicationContext applicationContext;    @Override    public void setApplicationContext(ApplicationContext context) throws BeansException {        applicationContext = context;    }    @Test    public void testA() {        System.out.println("testA>>>"+applicationContext.getBean(ConditionalTest.class));    }}

关于ApplicationContextAware使用理解参考

可以看出这个ConditionalTest被注入了:

如果你去掉这个配置测试用例就会报错找不到这个bean:

自定义conditional注解实现

 

自定义注解引入condition接口实现类

@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documented@Conditional(MyCondition.class)public @interface MyConditionAnnotation {    String[] value() default {};}

实现一个自定义注解

实现Condition接口重写matches方法,符合条件返回true

public class MyCondition implements Condition {    @Override    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {        String[] properties = (String[])metadata.getAnnotationAttributes("com.paopaoedu.springboot.condition.MyConditionAnnotation").get("value");        for (String property : properties) {            if (StringUtils.isEmpty(context.getEnvironment().getProperty(property))) {                return false;            }        }        return true;    }}

引入conditional注解

@Component@MyConditionAnnotation({"spring.redis.master.host", "spring.redis.follow.host"})public class ConditionalTest2 {}

配置文件

# Redis服务器地址spring.redis.master.host=r-xxx1.redis.rds.aliyuncs.com# Redis服务器连接端口spring.redis.master.port=6379# Redis服务器连接密码(默认为空)spring.redis.master.password=# Redis服务器地址spring.redis.follow.host=r-xxx2.redis.rds.aliyuncs.com# Redis服务器连接端口spring.redis.follow.port=6379# Redis服务器连接密码(默认为空)spring.redis.follow.password=

修改测试用例

@RunWith(SpringRunner.class)@SpringBootTest(classes = {SpringBootLearningApplication.class})//不用类似new ClassPathXmlApplicationContext()的方式,从已有的spring上下文取得已实例化的bean。通过ApplicationContextAware接口进行实现。public class SpringBootLearningApplicationTests implements ApplicationContextAware {    private ApplicationContext applicationContext;    @Override    public void setApplicationContext(ApplicationContext context) throws BeansException {        applicationContext = context;    }    @Test    public void testA() {        System.out.println("testA>>>"+applicationContext.getBean(ConditionalTest.class));        System.out.println("testA>>>"+applicationContext.getBean(ConditionalTest2.class));    }}

输出

 

重要的调试断点ClassPathScanningCandidateComponentProvider.scanCandidateComponents()

private Set
scanCandidateComponents(String basePackage) { Set
candidates = new LinkedHashSet<>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } if (resource.isReadable()) { try { MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } else { if (debugEnabled) { logger.debug("Ignored because not a concrete top-level class: " + resource); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; }

转载地址:https://linuxstyle.blog.csdn.net/article/details/104345464 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Springboot源码分析之内嵌tomcat源码分析
下一篇:springboot集成logback日志 通用logback.xml模板详解

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月15日 00时18分27秒