一、接口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(); }

通常配合使用。

示例:

接口:EncodingConvert

package com.lhx.spring.springboot_auto_config;

public interface EncodingConvert {

}

接口实现一:UTF8EncodingConvert

package com.lhx.spring.springboot_auto_config;

public class UTF8EncodingConvert implements EncodingConvert {

}

接口实现二:GBKEncodingConvert

package com.lhx.spring.springboot_auto_config;

public class GBKEncodingConvert implements EncodingConvert {

}

配置类:

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();
}
}

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();
}
}

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

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;
} }

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;
} }

修改配置类

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();
}
}

此时,会发现会根据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 () -> {
};
} }

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();
}
}

默认是不能装配的

可以再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

006-Spring Boot自动配置-Condition、Conditional、Spring提供的Conditional自动配置的更多相关文章

  1. Spring Boot 揭秘与实战 自己实现一个简单的自动配置模块

    文章目录 1. 实战的开端 – Maven搭建 2. 参数的配置 - 属性参数类 3. 真的很简单 - 简单的服务类 4. 自动配置的核心 - 自动配置类 5. spring.factories 不要 ...

  2. 峰哥说技术:06-手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理

    Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 06  峰哥说技术:手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理 Sp ...

  3. Spring Boot干货系列:(七)默认日志框架配置

    Spring Boot干货系列:(七)默认日志框架配置 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候, ...

  4. Spring Boot 项目学习 (二) MySql + MyBatis 注解 + 分页控件 配置

    0 引言 本文主要在Spring Boot 基础项目的基础上,添加 Mysql .MyBatis(注解方式)与 分页控件 的配置,用于协助完成数据库操作. 1 创建数据表 这个过程就暂时省略了. 2 ...

  5. Spring Boot 2.X(四):Spring Boot 自定义 Web MVC 配置

    0.准备 Spring Boot 不仅提供了相当简单使用的自动配置功能,而且开放了非常自由灵活的配置类.Spring MVC 为我们提供了 WebMvcConfigurationSupport 类和一 ...

  6. Spring Boot 框架下使用MyBatis访问数据库之基于XML配置的方式

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML ...

  7. spring boot系列(五)spring boot 配置spring data jpa (查询方法)

    接着上面spring boot系列(四)spring boot 配置spring data jpa 保存修改方法继续做查询的测试: 1 创建UserInfo实体类,代码和https://www.cnb ...

  8. Spring Boot 揭秘与实战 附录 - Spring Boot 公共配置

    Spring Boot 公共配置,配置 application.properties/application.yml 文件中. 摘自:http://docs.spring.io/spring-boot ...

  9. Spring Boot教程(三十八)使用MyBatis注解配置详解(1)

    之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...

  10. 【转】Spring Boot 构建应用——快速构建 Spring Boot 应用

    Spring Boot 简化了 Spring 应用开发,不需要配置就能运行 Spring 应用,Spring Boot 的自动配置是通过 Spring 4.x 的条件注解 @Conditional 来 ...

随机推荐

  1. some problem

    CF1257F Make Them Similar $solution:$ 折半搜索后考虑如何维护两个数组的和,可以将 $A$ 中每个数减 $A_1$ ,$B$ 中每个数被减 $B_1$ ,$map$ ...

  2. Restful风格API中用put还是post做新增操作有什么区别?

    Restful风格API中用put还是post做新增操作有什么区别? 转 头条面试归来,有些话想和Java开发者说!>>> 这个是华为面试官问我的问题,回来我找了很多资料,想验证这个 ...

  3. Datatable 中的数据查询(查询不重复记录)

    http://blog.csdn.net/lovexiaoxiao/article/details/3734932 //在sql中我们使用distinct查询不重复记录    //然而我在项目中表关系 ...

  4. MongoDB的使用学习之(五)Spring集成MongoDB以及简单的CRUD

    这篇文章不错:Spring Data - MongoDB 教程 (1.0.0.M1)http://miller-cn.iteye.com/blog/1258859 1.介绍 之前在很多地方一直见到这个 ...

  5. NSString用法,object-C数组以及字符串拼接和分割

    一.介绍使用NSString创建一个字符串的代码如下: #import <Foundation/Foundation.h>int main (int argc, char *argv[]) ...

  6. 03python面向对象编程之Python中单下划线和双下划线的区别7

    通常Python类中会有_和__的方法,是指什么意思呢?如下: 双下划线表示内部不允许访问,一个下划线表示这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽 ...

  7. <authentication> 元素

    <authentication> 元素 配置 ASP.NET 身份验证支持.该元素只能在计算机.站点或应用程序级别声明.如果试图在配置文件中的子目录或页级别上进行声明,则将产生分析器错误信 ...

  8. CF1103D Codeforces Round #534 (Div. 1) Professional layer 状压 DP

    题目传送门 https://codeforces.com/contest/1103/problem/D 题解 失去信仰的低水平选手的看题解的心路历程. 一开始看题目以为是选出一些数,每个数可以除掉一个 ...

  9. ES6 Module(模块)

    1.export命令 一个模块就是一个独立的文件. 该文件内部的所有变量,外部无法获取. 如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量. 下面是一个 JS 文件,里 ...

  10. lvm磁盘扩展

    pvcreate /dev/sddpvdisplay /dev/sddvgdisplayvgextend VolGroup_02 /dev/sddlvextend -L +50G /dev/mappe ...