一、接口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. luogu P5331 [SNOI2019]通信

    传送门 有匹配次数限制,求最小代价,这显然是个费用流的模型.每个点暴力和前面的点连匹配边,边数是\(n^2\)的. 然后发现可以转化成一个set,每次加入一个点,然后入点对set里面的出点连边.这个s ...

  2. 爬虫之selenium 安装与 chromedriver安装

    今天学到一个有意思的插件,就是chromedriver,在爬虫的时候,如果网站反爬虫做的很好,自己又很想爬去里面的数据,那就可以用这个插件,虽然笨笨的,慢的一批,但是还有别的办法就不会用他啦, 这个东 ...

  3. 吴恩达深度学习:2.3梯度下降Gradient Descent

    1.用梯度下降算法来训练或者学习训练集上的参数w和b,如下所示,第一行是logistic回归算法,第二行是成本函数J,它被定义为1/m的损失函数之和,损失函数可以衡量你的算法的效果,每一个训练样例都输 ...

  4. 时间戳转换日期格式 - Vue

    日常开发中经常会遇到时间相关的问题,服务端返回的数据都是以时间戳的方式,那么需要将其处理转化为对应的时间格式,具体方式如下: 一.filters 中 formatDate 方法实现 <scrip ...

  5. HTTPS原理以及流程

    一.HTTP和HTTPS的区别 HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全. HTTPS协议是由SSL+HTTP协议构建的可进行加密传输.身份认证的网 ...

  6. 04-A的LU分解

    一.矩阵$AB$的逆 $(AB)^{-1}=B^{-1}A^{-1}$,顺序正好相反 二.$A=LU$ 如矩阵: $\left[\begin{array}{ll}{2} & {1} \\ {8 ...

  7. Effective C++条款05:了解C++默默编写并调用哪些函数

    class Empty{}; class Empty{ Empty(){}; Empty(const Empty& rhs){}; ~Empty(){}; Empty& operato ...

  8. ubuntu 安装nvidia driver

    错误的命令:sudo apt-get install nvidiar-430好多教程都是这样 sudo apt-get install nvidia-driver-430  很奇怪这个命令变成这样 h ...

  9. mysql 数据库url

    jdbc:mysql://localhost:3306/database?useUnicode=true&useJDBCCompliantTimezoneShift=true&useL ...

  10. 进程队列补充、socket实现服务器并发、线程完结

    目录 1.队列补充 2.关于python并发与并行的补充 3.TCP服务端实现并发 4.GIL全局解释器锁 什么是保证线程安全呢? GIL与Lock 5.验证多线程的作用 对结论的验证: 6.死锁现象 ...