zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Study Plan The TwentySecond Day
    Study Plan The Nineteenth Day
    Study Plan The TwentySeventh Day
    Study Plan The Twentieth Day
    Study Plan The TwentyFirst Day
    python实现进程的三种方式及其区别
    yum makecache
    JSONPath 表达式的使用
    oracle执行cmd的实现方法
    php daodb插入、更新与删除数据
  • 原文地址:https://www.cnblogs.com/bjlhx/p/8326032.html
Copyright © 2011-2022 走看看