• 006-Spring Boot自动配置-Condition、Conditional、Spring提供的Conditional自动配置


    一、接口Condition、Conditional(原理)

    主要提供一下方法

    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

    true:表示装配

    false:表示不装配

    1.1、Conditional

      在Spring4中引入,其主要作用就是判断条件是否满足,从而决定是否初始化并向容器注册Bean

    注解:Conditional() 参数是数组,数组内的都是true才装配

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
    
        /**
         * All {@link Condition}s that must {@linkplain Condition#matches match}
         * in order for the component to be registered.
         */
        Class<? extends Condition>[] value();
    
    }
    View Code

    通常配合使用。

    示例:

    接口:EncodingConvert

    package com.lhx.spring.springboot_auto_config;
    
    public interface EncodingConvert {
    
    }
    View Code

    接口实现一:UTF8EncodingConvert 

    package com.lhx.spring.springboot_auto_config;
    
    public class UTF8EncodingConvert implements EncodingConvert {
    
    }
    View Code

    接口实现二:GBKEncodingConvert

    package com.lhx.spring.springboot_auto_config;
    
    public class GBKEncodingConvert implements EncodingConvert {
    
    }
    View Code

    配置类:

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    
    @SpringBootConfiguration
    public class EncodingConvertConfiguration {
        @Bean
        public EncodingConvert createGBKEncodingConvert() {
            return new GBKEncodingConvert();
        }
    
        @Bean
        public EncodingConvert createUTF8EncodingConvert() {
            return new UTF8EncodingConvert();
        }
    }
    View Code

    App:

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.Conditional;
    
    @SpringBootApplication
    public class App {
        @Bean
        public Runnable createRunnable() {
            return () -> {
                System.out.println("spring boot is running");
            };
        }
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
            context.getBean(Runnable.class).run();
            //可以通过启动参数修改-Dfile.encoding=GBK
            System.out.println(System.getProperty("file.encoding"));
            System.out.println(context.getBeansOfType(EncodingConvert.class));
            context.close();
        }
    }
    View Code

    此时,会发现连个接口实现都会被装配进来。

    UTF8Condition实现Condition接口

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class UTF8Condition implements Condition {
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String encoding = System.getProperty("file.encoding");
            if (encoding != null) {
                return "utf-8".equalsIgnoreCase(encoding);
            }
            return false;
        }
    
    }
    View Code

    GBKCondition实现Condition接口

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class GBKCondition implements Condition {
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String encoding = System.getProperty("file.encoding");
            if (encoding != null) {
                return "gbk".equalsIgnoreCase(encoding);
            }
            return false;
        }
    
    }
    View Code

    修改配置类

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    
    @SpringBootConfiguration
    public class EncodingConvertConfiguration {
        @Bean
        @Conditional(GBKCondition.class)
        public EncodingConvert createGBKEncodingConvert() {
            return new GBKEncodingConvert();
        }
    
        @Bean
        @Conditional(UTF8Condition.class)
        public EncodingConvert createUTF8EncodingConvert() {
            return new UTF8EncodingConvert();
        }
    }
    View Code

    此时,会发现会根据file.encoding值来装配接口类。

    可在启动参数增加

      -Dfile.encoding=GBK  

      

    然后调试,发现装配类也变了

    注意:@Conditional也可以作用在类上

     二、Spring提供的Conditional自动配置

    jar:spring-boot-autoconfigure中,org.springframework.boot.autoconfigure.condition;即spring-boot提供

    ConditionalOnBean:当存在某个bean时候装配

    ConditionalOnMissingBean:当不存在某个bean时候装配注解的bean

    ConditionalOnClass:当classpath有才装配

    ConditionalOnExpression:

    ConditionalOnJava:JDK版本符合时候才装配

    ConditionalOnNotWebApplication:不是web环境才装配

    ConditionalOnWebApplication:是web环境才装配

    ConditionalOnResource:资源存在才装配

    ConditionalOnProperty:配置存在才装配

    2.1、ConditionalOnProperty 配置存在匹配时候才配置

    增加配置类

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Bean;
    
    @SpringBootConfiguration
    public class UserConfiguration {
    
        @Bean
        @ConditionalOnProperty(name = "runnable.enable", havingValue = "true")
        public Runnable createRunnable() {
            return () -> {
            };
        }
    
    }
    View Code

    App2编写

    package com.lhx.spring.springboot_auto_config;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.Conditional;
    
    @SpringBootApplication
    public class App2 {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(App2.class, args);
            System.out.println(context.getBeansOfType(Runnable.class));
            context.close();
        }
    }
    View Code

    默认是不能装配的

    可以再application.properties中添加runnable.enable=true即可装配

    或者@ConditionalOnProperty(name = "runnable.enable", havingValue = "true")增加

    matchIfMissing=true,表示配置没有的时候也生效

    2.2、ConditionalOnClass classpath 有某个类才装配

    增加或删除maven,查看效果

            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.8.2</version>
            </dependency>

    使用代码

        @Bean
        @ConditionalOnClass(name="com.google.gson.Gson")
        public Runnable createGsonRunnable() {
            return () -> {
            };
        }

    2.3、ConditionalOnBean:根据容器中是否存在某个Bean进行装配

        @Bean
        @ConditionalOnBean(name="user")
        public Runnable createOnBeanRunnable() {
            return () -> {
            };
        }

    示例一、根据配置选择不同的实现类注入

    需求:根据配置选择不同的实现类注入,有个业务逻辑,有两套模式,大部分功能流程一致,但涉及某些实现不一致,标准的模板模式:004-行为型-02-模板方法模式(Template Method)

     实际使用中会有,默认是一种实现,如果有某个配置,则生效。可以参看springboot自动装配实现,如Cache等

    实现:https://github.com/bjlhx15/common.git   spring-framework-core/spring-aop/testconditional

    基础业务接口

    public interface ITestConditionalService {
        String getBefore();
        String get();
    }

    如果新增业务需要新增配置

    public class ConstBean {
        public final static String atest="atest";
        public final static String btest="btest";
    }

    抽象类实现公共方案步骤

    public abstract class AbstractTestConditionalService implements ITestConditionalService {
    
        @Override
        public abstract String getBefore();
    
        @Override
        public String get() {
            String before = this.getBefore();
            // do something
            return "before:" + before;
        }
    }

    第一种实现方案:也就是默认方案

    @Service("aTestConditionalServiceImpl")
    @ConditionalOnProperty(name = "set.test",havingValue = ConstBean.atest,matchIfMissing = true)
    public class ATestConditionalServiceImpl extends AbstractTestConditionalService {
        @Override
        public String getBefore() {
            return "atest test";
        }
    }

    第二种方案

    @Service("bTestConditionalServiceImpl")
    @ConditionalOnProperty(name = "set.test",havingValue = ConstBean.btest)
    public class BTestConditionalServiceImpl extends AbstractTestConditionalService {
        @Override
        public String getBefore() {
            return "btest test";
        }
    }

    配置 如果是a逻辑可默认不写

    # 配置实现 atest、btest
    set.test=atest
  • 相关阅读:
    【转】如何正确复制CSDN文章到自己的博客
    【转】Win10双网卡优先顺序设置
    Android studio中生成javadoc
    【转】HTML5 布局固定宽度
    字节跳动静态资源公共库
    【转】Android studio中生成javadoc
    怎么选择 Go 文件读取方案
    prometheus存储
    gogorm的预加载 preload或related方法使用场景(外键)
    go的gin跨域中间件
  • 原文地址:https://www.cnblogs.com/bjlhx/p/8326032.html
Copyright © 2020-2023  润新知