[Day - 06 ] - Spring Conditional 运用与原理

Abstract

当每个开发者初始化一套服务时,可能会因不同的系统或不同的Java版本相容性问题进而产生不同的Bean元件,故在此Spring 框架提供了多种条件判断各种Bean是否要建立於IoC配置连接池中,并以设计好18种相容於既有Spring 框架的Conditional注解(Annotation)提供开发者做延用,若没有开发者预期的Conditional注解(Annotation)类别元件,开发者可自行进行继承实作Condition注解类别中的matches方法,进而去判断相关的Bean是否建立於Spring IoC配置连接池中,。

Principle Introduction

@Conditional是Spring 4之後新提供的注解,主要是用来判断是否注册各类型的Bean类别元件接口,每个Conditional注解都会配置一个条件,当满足此条件会将此Bean类别元件注册於IoC配置连接池中,此注解我们可配置在类别(Class)与方法(Method)上,在於Conditional注解上分为两种,一种是原生Spring提供,另一种为客制化动态配置类别,接下来我们将依照下方程序区段进行延伸讨论。

  1. 原生Condition 注解判断类型,我们将提供,我们将针对这19种Spring框架所提供的Conditional进行分析

1.1 ConditionalOnBean : IoC配置持已存在指定的Bean类别元件条件下,才可以建立此Bean类别元件。

    @Bean("Pomeranian")
    @ConditionalOnBean(name="Weisting")
    public Dog getAnimalOfDog() {
        Dog dog = new Dog();
        dog.setName("Pomeranian");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.2 ConditionalOnClass : 目前专案存在指定的类别存在下,才可建立此Bean类别元件。

    @Bean("TBaby")
    @ConditionalOnClass(Animal.class)
    public Turtle getAnimalOfTurtle() {
        Turtle turtle = new Turtle();
        turtle.setName("TBaby");
        turtle.setType("Turtle");
        turtle.setBehavior("Climb");
        return turtle;
    }

1.3 ConditionalOnMissingBean : IoC配置持不存在指定的Bean类别元件条件下,才可以建立此Bean类别元件。

   @Bean("malzis")
    @ConditionalOnMissingBean(name="Pomeranian")
    public Dog getAnimalOfDogWithMalzis() {
        Dog dog= new Dog();
        dog.setName("malzis");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.4 ConditionalOnMissingClass : 目前专案不存在指定的类别存在下,才可建立此Bean类别元件。

    @Bean("lucky")
    @ConditionalOnMissingClass(value = {"sw.spring.conditional.model.Cat"})
    public Dog getAnimalOfDogWithLucky() {
        Dog dog= new Dog();
        dog.setName("lucky");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.5 ConditionalOnWebApplication : 目前专案为一套WEB开发项目下,才可建立此Bean类别元件。

    @Bean("husky")
    @ConditionalOnWebApplication
    public Dog getAnimalOfDogWithHusky() {
        Dog dog= new Dog();
        dog.setName("husky");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.6 ConditionalOnNotWebApplication : 目前专案不是为一套WEB开发项目下,才可建立此Bean类别元件。

    @Bean("ghost")
    @ConditionalOnNotWebApplication
    public Dog getAnimalOfDogWithGhost() {
        Dog dog= new Dog();
        dog.setName("ghost");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.8 ConditionalOnProperty : 目前专案已存在指定的Properties下,才可建立此Bean类别元件。

    @Bean("Bernard")
    @ConditionalOnProperty(prefix = "sw.spring.conditional",name = "assert",havingValue = "true")
    public Turtle getAnimalOfTurtleWithBernard() {
        Turtle turtle = new Turtle();
        turtle.setName("Bernard");
        turtle.setType("Turtle");
        turtle.setBehavior("Climb");
        return turtle;
    }

1.9 ConditionalOnJava : 目前专案已存在Java指定的版本下,才可建立此Bean类别元件。

    @Bean("schnauzer")
    @ConditionalOnJava(JavaVersion.FIFTEEN)
    public Dog getAnimalOfTurtleWithSchnauzer() {
        Dog dog= new Dog();
        dog.setName("schnauzer");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.10 ConditionalOnExpression : 满足SpEL表达式作为判断条件下,才可建立此Bean类别元件。

    @Bean("dylan")
    @ConditionalOnExpression("#{'true'.equals(environment['sw.spring.conditional.assert'])}")
    public Dog getAnimalOfDogWithDylan() {
        Dog dog = new Dog();
        dog.setName("dylan");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.11 ConditionalOnResource : 目前专案已存在指定的资源类别,才可建立此Bean类别元件。

    @Bean("resource")
    @ConditionalOnResource( resources = "classpath:/application.properties")
    public Dog getAnimalOfDogWithResource() {
        Dog dog = new Dog();
        dog.setName("resource");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.12 ConditionalOnSingleCandidate : 在IoC配置池中存在指定的Bean类别元件,且为主要首选的Bean类别元件,才可建立此Bean类别元件。

    @Bean("robert")
    @ConditionalOnSingleCandidate(ApplicationBoot.class)
    public Dog getAnimalOfDogWithSingleCandidate() {
        Dog dog = new Dog();
        dog.setName("robert");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.13 ConditionalOnRepositoryType : 当特定类别有指定的存储库类型(RepositoryType)存在下[其类型分为:AUTO、IMPERATIVE、NONE及REACTIVE其四种],才可建立此Bean类别元件。

    @Bean("JPA-Repository")
    @ConditionalOnRepositoryType(store = "JPA-Repository",type= RepositoryType.NONE)
    public Turtle getAnimalOfFlyTurtle() {
        Turtle turtle = new Turtle();
        turtle.setName("JPA-Repository");
        turtle.setType("Turtle");
        turtle.setBehavior("Climb");
        return turtle;
    }

1.14 ConditionalOnWarDeployment : 目前专案只在war包中运作中,才可建立此Bean类别元件。

    @Bean("war")
    @ConditionalOnWarDeployment
    public Dog getAnimalOfDogWithJNDI() {
        Dog dog = new Dog();
        dog.setName("war");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

1.15 ConditionalOnJndi : 若JNDI InitialContext 中的存在可用和可以查找指定位置的条件,才可建立此Bean类别元件。

1.16 ConditionalOnCloudPlatform : 若此服务建立在云端平台服务上,目前支援仅Cloud Foundry platform、Heroku platform、SAP Cloud platform及 Kubernetes platform其四项云端平台,才可建立此Bean类别元件。

1.17 ConditionalOnDefaultWebSecurity : 如果系统有预设Web 安全的默认配置。 且此设定会依赖Spring Framework Security套件,其套件为规范条件各类使用者运用何种身份验证,才可建立此Bean类别元件。

1.18 ConditionalOnMissingFilterBean : 某个FilterBean元件类别的对象不存在时,才可建立此Bean类别元件。

1.19 ConditionalOnEnabledResourceChain : 会依据ResourceProperties中进行判断三项资源是否启用与存在,分别为spring.resources.chain.strategy.fixed.enabled、spring.resources.chain.strategy.content.enabled及spring.resources.chain.enabled,若不存在,则判断是否存在org.webjars.WebJarAssetLocator套件,进行判断资源是否匹配,才可建立此Bean类别元件。

2.若要客制化一个Conditional类别,必须建立一个类别并进行继承与实作,并将此类别条件配置於该Conditional注解中,相关片段程序码如下。

public class MacCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").contains("Mac");
    }
}


---

   @Bean("machine")
    @Conditional(MacCondition.class)
    public Dog getAnimalOfDogWithMachine() {
        Dog dog = new Dog();
        dog.setName("machine");
        dog.setType("Dog");
        dog.setSound("Wong ! Wong ! Wong !");
        return dog;
    }

Structure

在Conditional注解的结构中,必须预设配置一个继承Condition介面的类别元件,此类别会实作matches的一个方法,透过此方法进行判断是否符合条件,故无论是否为Spring框架所提供的各类Conditional注解,或开发者自身客制化的Condition条件逻辑方法,都会经由主要的核心注解(Conditional)进行请求判断(invoke)。
image
图一 Conditional 架构图

Follow up

Run test task

gradle test

Run open result html

open ./build/reports/tests/test/index.html

Test Report

Test Class Sample
image

Test Details.
image

Sample Source

spring-conditional-sample

Reference Url

Auto Configure Condition

@Conditional注解 -【Spring底层原理】

SpringBoot自动配置的魔力

springboot-web-01


<<:  [重构倒数第10天] - 行动装置上面的 Touch 跟 Click

>>:  【在 iOS 开发路上的大小事-Day09】将常用的 Function 写成一个 class,让各个档案都能使用

Day 17 - WooCommerce 测试环境建立 (上)

相信大家都可以把 WordPress 架起来了,因此就从安装 WooCommerce 开始吧! 安装...

EP29 - 秽土转生~到了 AWS 也要能够备份~

在 EP13 - 灾难演练,重建你的 VPC, 我们在重建 VPC 之前, 有带着大家怎麽进行单次备...

CMoney软件工程师战斗营_专题制作改善ui/ux_Week 19

在这里我就直接开门见山丢上我最终画面了 网站(再过几天服务应该就会到期) http://crypto...

Day 25. Hashicorp Vault: Diagnose Vault server

Hashicorp Vault: Diagnose Vault server 这是Vault 1.8...

Material UI in React [Day 3] Layout (Grid & ThemeProvider)

Grid 今天要讲解的是Grid排版的部分,如果是有使用过bootstrap的经验的朋友,其实它的逻...