SpringBoot系列---Spring条件注解

一 @Conditional扩展注解

必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效

注解名称 作用
@Conditional 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

1.1 Bean作为条件

1.1.1 @ConditionalOnBean

组合 @Conditional 注解,当容器中有指定的 Bean 才开启配置。
这个注解用于检测容器中是否包含指定的bean。如下图:
SpringBoot系列---Spring条件注解_第1张图片
除了可以用Class指定bean外,还可以使用类的全名称,还可以使用bean名称(即beanName)。

还可以使用注解指定是否包含标有该注解的bean。

示例中是通过Class来指定的,而且指定的是之前注册过的bean,所以一定能匹配上。
执行结果如下图:
在这里插入图片描述
注:@ConditionalOnMissingBean注解原理一样,只不过是否定性的匹配而已。

1.1.2 @ConditionalOnMissingBean

组合 @Conditional 注解,和 @ConditionalOnBean 注解相反,当容器中没有指定的 Bean 才开启配置

1.1.3 @ConditionalOnSingleCandidate

这个注解用于检测容器中能够匹配上的候选bean是否只有一个。

只有一个是什么意思呢?就是某个类只注册了一次,这时就是只有一个。比如Boss类。

但是员工可以有多个,所以就会有多个Staff类被注册。此时就不满足条件了。

如果此时还想满足的话,就必须在其中一个Staff类注册时标上@Primary注解。
SpringBoot系列---Spring条件注解_第2张图片
因为我们指定的bean只注册了一次,所以一定满足条件。
在这里插入图片描述

1.2 类作为条件

1.2.1 @ConditionalOnClass

组合 @Conditional 注解,当容器中有指定的 Class 才开启配置。
这个注解用于检测类路径里是否包含某个类,其实就是确定是否引入了指定的依赖。
SpringBoot系列---Spring条件注解_第3张图片
因为我用的JDK1.8,肯定有这个类,所以会匹配上,结果如下图:

注:@ConditionalOnMissingClass注解原理一样,只不过是否定性的匹配而已。

1.2.2 @ConditionalOnMissingClass

组合 @Conditional 注解,和 @ConditionalOnMissingClass 注解相反,当容器中没有指定的 Class 才开启配置。

1.3 @ConditionalOnExpression SpEL表达式作为条件

@ConditionalOnExpression 组合 @Conditional 注解,当 SpEL 表达式为 true 时才开启配置。

1.4 @ConditionalOnJava JAVA版本作为判断条件

@ConditionalOnJava 组合 @Conditional 注解,当运行的 Java JVM 在指定的版本范围时才开启配置。

1.5 @ConditionalOnProperty 配置属性作为判断条件

@ConditionalOnProperty 组合 @Conditional 注解,当指定的属性有指定的值时才开启配置。
这个注解用于检测Environment中的指定属性是否存在或等于某个指定的值。
SpringBoot系列---Spring条件注解_第4张图片
如havingValue属性没有指定的话,那么只要实际属性值不等于false,都算匹配成功。如果指定了,那就必须要一样才行。

matchIfMissing属性就是说,如果没有发现这个属性,算不算匹配上,设置为true就算,false就不算,默认为不算。

请看配置文件,如下图:
在这里插入图片描述
很明显,这是可以匹配上的,运行一下,结果如下图:
可以看到,对应的类被注册了bean定义。

1.6 @ConditionalOnResource 资源文件是否存在作为判断条件

这个注解用于检测类路径中是否包含指定的资源。一般也就是文件了。

@ConditionalOnResource组合 @Conditional 注解,当类路径下有指定的资源才开启配置
@ConfigurationProperties 用来加载额外的配置(如 .properties 文件),可用在 @Configuration 注解类,或者 @Bean 注解方法上面。
@EnableConfigurationProperties 一般要配合 @ConfigurationProperties 注解使用,用来开启对 @ConfigurationProperties 注解配置 Bean 的支持。
@ImportResource 这是 Spring 3.0 添加的新注解,用来导入一个或者多个 Spring 配置文件,这对 Spring Boot 兼容老项目非常有用,因为有些配置无法通过 Java Config 的形式来配置就只能用这个注解来导入

@Import 这是 Spring 3.0 添加的新注解,用来导入一个或者多个 @Configuration 注解修饰的类,这在 Spring Boot 里面应用很多。

SpringBoot系列---Spring条件注解_第5张图片
肯定是存在的,执行结果如下图:
在这里插入图片描述

1.7 是否Web应用作为判断条件

1.7.1 @ConditionalOnWebApplication

组合 @Conditional 注解,当前项目类型是 WEB 项目才开启配置。

1.7.2 @ConditionalOnNotWebApplication

组合 @Conditional 注解,和 @ConditionalOnWebApplication 注解相反,当前项目类型不是 WEB 项目才开启配置。

二 @Conditional自定义

2.1 定义注解

需要实现一个条件接口,如下图:

SpringBoot系列---Spring条件注解_第6张图片
只有一个方法,返回true表示匹配上,false则相反。方法的第一个参数,是一个上下文,这里有很多的东西供我们使用。如下图:

SpringBoot系列---Spring条件注解_第7张图片
方法的第二个参数,是最终标有我们定义好的条件注解的那个类,这个一定要明白。

2.2 定义注解接口实现类

我们来定义两个和操作系统对应的注解,一个用于Windows,一个用于Linux。
Windows版本的实现。从Environment中读出操作系统的名称,看是否包含windows即可,如下图:

SpringBoot系列---Spring条件注解_第8张图片
Linux版本的实现,原理和刚刚的一样,如下图:
SpringBoot系列---Spring条件注解_第9张图片

2.3 模仿springbootboot启动类注解

再定义两个注解,分别和这两个条件实现类关联起来。Windows版本的,如下图
SpringBoot系列---Spring条件注解_第10张图片
Linux版本的,如下图:
SpringBoot系列---Spring条件注解_第11张图片

2.4 使用自定义注解

然后开始试用一下这两个条件注解,如下图:
SpringBoot系列---Spring条件注解_第12张图片
因为我用的是Windows,所以肯定只有@Windows注解可以匹配。

在这里插入图片描述
这只是一个简单的示例,可以根据自己的需要定义更加复杂的,但是原理和流程都是一样的。

三 springboot 相关的注解

@ConditionalOnJndi

组合 @Conditional 注解,当指定的 JNDI 存在时才开启配置。

@AutoConfigureAfter

用在自动配置类上面,表示该自动配置类需要在另外指定的自动配置类配置完之后。

如 Mybatis 的自动配置类,需要在数据源自动配置类之后。

@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
}

@AutoConfigureBefore

这个和 @AutoConfigureAfter 注解使用相反,表示该自动配置类需要在另外指定的自动配置类配置之前。

@SpringBootApplication

这是 Spring Boot 最最最核心的注解,用在 Spring Boot 主类上**,标识这是一个 Spring Boot 应用,标识启动类**,用来开启 Spring Boot 的各项能力。

其实这个注解就是 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 这三个注解的组合,也可以用这三个注解来代替 @SpringBootApplication 注解。

@EnableAutoConfiguration

允许 Spring Boot 自动配置注解,开启这个注解之后,Spring Boot 就能根据当前类路径下的包或者类来配置 Spring Bean。

如:当前类路径下有 Mybatis 这个 JAR 包,MybatisAutoConfiguration 注解就能根据相关参数来配置 Mybatis 的各个 Spring Bean。

@Configuration

这是 Spring 3.0 添加的一个注解,用来代替 applicationContext.xml 配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。

@SpringBootConfiguration

这个注解就是 @Configuration 注解的变体,只是用来修饰是 Spring Boot 配置而已,或者可利于 Spring Boot 后续的扩展。
@ComponentScan
这是 Spring 3.1 添加的一个注解,用来代替配置文件中的 component-scan 配置,开启组件扫描,即自动扫描包路径下的 @Component 注解进行注册 bean 实例到 context 中。

转载 :前面 5 个注解可以在Java技术栈的这篇文章《Spring Boot 最核心的 3 个注解详解》中了解更多细节的。
https://zhuanlan.zhihu.com/p/57689422

springboot自动的启动配置类

redis

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

mybatis的自动配置类

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
    private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
    private final MybatisProperties properties;
    private final Interceptor[] interceptors;
    private final TypeHandler[] typeHandlers;
    private final LanguageDriver[] languageDrivers;
    private final ResourceLoader resourceLoader;
    private final DatabaseIdProvider databaseIdProvider;
    private final List configurationCustomizers;

    public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider interceptorsProvider, ObjectProvider typeHandlersProvider, ObjectProvider languageDriversProvider, ResourceLoader resourceLoader, ObjectProvider databaseIdProvider, ObjectProvider> configurationCustomizersProvider) {
        this.properties = properties;
        this.interceptors = (Interceptor[])interceptorsProvider.getIfAvailable();
        this.typeHandlers = (TypeHandler[])typeHandlersProvider.getIfAvailable();
        this.languageDrivers = (LanguageDriver[])languageDriversProvider.getIfAvailable();
        this.resourceLoader = resourceLoader;
        this.databaseIdProvider = (DatabaseIdProvider)databaseIdProvider.getIfAvailable();
        this.configurationCustomizers = (List)configurationCustomizersProvider.getIfAvailable();
    }

    public void afterPropertiesSet() {
        this.checkConfigFileExists();
    }

    private void checkConfigFileExists() {
        if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
            Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
            Assert.state(resource.exists(), "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
        }

    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }

        this.applyConfiguration(factory);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }

        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }

        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }

        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }

        if (this.properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
        }

        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }

        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            factory.setTypeHandlers(this.typeHandlers);
        }

        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }

        Set factoryPropertyNames = (Set)Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
        Class defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
        if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
            factory.setScriptingLanguageDrivers(this.languageDrivers);
            if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
                defaultLanguageDriver = this.languageDrivers[0].getClass();
            }
        }

        if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
            factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
        }

        return factory.getObject();
    }

    private void applyConfiguration(SqlSessionFactoryBean factory) {
        org.apache.ibatis.session.Configuration configuration = this.properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
            configuration = new org.apache.ibatis.session.Configuration();
        }

        if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
            Iterator var3 = this.configurationCustomizers.iterator();

            while(var3.hasNext()) {
                ConfigurationCustomizer customizer = (ConfigurationCustomizer)var3.next();
                customizer.customize(configuration);
            }
        }

        factory.setConfiguration(configuration);
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        ExecutorType executorType = this.properties.getExecutorType();
        return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
    }

    @Configuration
    @Import({AutoConfiguredMapperScannerRegistrar.class})
    @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
        public MapperScannerRegistrarNotFoundConfiguration() {
        }

        public void afterPropertiesSet() {
            MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
        }
    }

    public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
        private BeanFactory beanFactory;

        public AutoConfiguredMapperScannerRegistrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
                MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
            } else {
                MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
                List packages = AutoConfigurationPackages.get(this.beanFactory);
                if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
                    packages.forEach((pkg) -> {
                        MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
                    });
                }

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
                builder.addPropertyValue("processPropertyPlaceHolders", true);
                builder.addPropertyValue("annotationClass", Mapper.class);
                builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
                BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
                Stream.of(beanWrapper.getPropertyDescriptors()).filter((x) -> {
                    return x.getName().equals("lazyInitialization");
                }).findAny().ifPresent((x) -> {
                    builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
                });
                registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
            }
        }

        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }
    }

你可能感兴趣的:(#,springboot,spring,boot)