满足条件的，才会被配置或构建。v2.1.4 后支持

| 属性 | 说明 | 
| -------- | -------- |
| onClass               | 有类（只能一个）     | 
| onClassName       | 有类名     | 
| onProperty           | 有属性（v3.6.0 后弃用）     | 
| onExpression       | 有 SnEL 表达式（v3.6.0 后支持）     | 
| onMissingBean     | 没有 Bean      | 
| onMissingBeanName   | 没有 Bean Name     | 
| onBean                     | 有 Bean。v2.9 后支持      | 
| onBeanName             | 有 Bean Name。v2.9 后支持     | 


关于“onClass”和“onClassName”：

* 检测类的本质其实是检查对应的依赖包是否引入了
* 同一个依赖包内的类，用一个即可；不同依赖包的类，建议分开检测

关于“onProperty”，有五用法：

* `${xxx.enable}`，有属性即可
* `${xxx.enable} == true`，有属性且==true（只支持==号，简单才高效；复杂的手写）
* `${xxx.enable:true} == true`，没属性（通过默认值加持）或者有属性且==true
* `${xxx.enable:true} != true`，没属性（通过默认值加持）或者有属性且!=true
* `${xxx.enable} && ${zzz.enable:true} == false`，“与”多条件
* `${yyy.name} == a`


关于“onExpression”（采用 [SnEL 表达式](/article/learn-solon-snel) ，使用更规范），有五用法：

* `${xxx.enable}`，有属性即可
* `${xxx.enable} == true`，有属性且==true
* `${xxx.enable:true} == true`，没属性（通过默认值加持）或者有属性且==true
* `${xxx.enable:true} != true`，没属性（通过默认值加持）或者有属性且!=true
* `${xxx.enable}  && (${zzz.mode:0} > 2 || ${xxx.mode:0} > 3)`，多条件
* `${yyy.name} == 'a'`（注意区别：字符串要和字符串比。强调类型相关性）

### 1、加在 `@Bean` 函数上

`@Bean` 函数可以返回 null，有些复杂的条件可以在函数内处理。

```java
@Configuration
public class DemoConfig{
    //检查否类有类存在，然后再产生它的bean
    @Bean
    //@Condition(onClassName="org.aaa.IXxxAaaImpl") //有类名
    @Condition(onClass=IXxxAaaImpl.class)  //有类
    public IXxx getXxx(){
        return new IXxxAaaImpl();
    }

    //检查有配置存在，然后再产生对应的bean
    @Bean
    //@Condition(onExpression="${yyy.enable}") //有属性值
    @Condition(onExpression="${yyy.enable:false} == true") //有属性值，且等于true
    public IYyy getYyy(@Inject("${yyy.config}") IYyyImpl yyy){
        return yyy;
    }
}
```

### 2、加在组件类上（任何组件类）

使用 onClass 条件时，组件不能继承自检测类。不然获取类元信息时直接会异常

* 例

```java
@Condition(onClass=XxxDemo.class) 
@Configuration
public class DemoConfig{ //DemoConfig 不能扩展自 XxxDemo
}

@Condition(onClass=XxxDemo.class) 
@Component
public class DemoCom{ //DemoCom 不能扩展自 XxxDemo
}
```

* 实例

```java
@Condition(onClass = SaSsoManager.class)
@Configuration
public class SaSsoAutoConfigure {
    @Bean
    public SaSsoConfig getConfig(@Inject(value = "${sa-token.sso}", required = false) SaSsoConfig ssoConfig) {
        return ssoConfig;
    }
    
    @Bean
    public void setSaSsoConfig(@Inject(required = false) SaSsoConfig saSsoConfig) {
        SaSsoManager.setConfig(saSsoConfig);
    }
    
    @Bean
    public void setSaSsoTemplate(@Inject(required = false) SaSsoTemplate ssoTemplate) {
        SaSsoUtil.ssoTemplate = ssoTemplate;
        SaSsoProcessor.instance.ssoTemplate = ssoTemplate;
    }
}
```

### 3、onMissingBean 条件与 List[Bean] 注入的边界

* onMissingBean 条件的执行时机为，Bean 扫描完成并检查之后才执行的
* List[Bean]（或 Map[String, Bean]） 注入，也是在 Bean 扫描完成后尝试注入的。

```java
@Configuration
public class TestConfig{
    @Condition(onMissingBean = Xxx.class)
    @Bean
    public Xxx aaa(){
        ...
    }

    @Condition(onMissingBean = Yyy.class)
    @Bean
    public Yyy bbb(List<Xxx> xxxList ){
        ...
    }

    @Condition(onMissingBean = Zzz.class)
    @Bean
    public Zzz ccc(List<Yyy> yyyList ){
        ...
    }
}
```

在 v2.8.0 之前，还有谁未完成注册？是不可知的（没有做依赖探测）。像上面的示例，xxxList 是好的，yyyList 可能会傻掉。xxxList 和 yyyList 是相同的注入时机（谁先谁后，无序），此时 Yyy 因为依赖 xxxList，所以并未生成。

以上注解方式，也可以采用手写方式处理：

```java
@Component
public class TestConfig implements LifecycleBean {
    @Inject
    AppContext context;

    @Override
    public void start() throws Throwable {
        if(!context.hasWrap(Xxx.class)){
            context.wrapAndPut(Xxx.class, new Xxx());
        }

        if(!context.hasWrap(Yyy.class)){
            List<Xxx> xxxList = context.getBeansOfType(Xxx.class);
            context.wrapAndPut(Yyy.class, new Yyy(xxxList));
        }

        if(!context.hasWrap(Zzz.class)){
            List<Yyy> yyyList = context.getBeansOfType(Yyy.class);
            context.wrapAndPut(Zzz.class, new Zzz(yyyList));
        }
    }
}
```