一、接口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

最新文章

  1. ABP模块化
  2. C、C++: 引用、指针、实例、内存模型、namespace
  3. [原创]android自定义动画的一点感悟
  4. svn更新项目时遇到被锁住的问题
  5. C#打开指定路径文件对话框
  6. R提高篇(一): 输入输出
  7. python 循环、循环设计、循环对象
  8. golang:slice陷阱
  9. DEDECMS中,常见全局变量
  10. jquery 点击查看,收起特效
  11. NOIP2011 观光公交
  12. [JavaScript] 初中级Javascript程序员必修学习目录
  13. 使用__doPostBack函数来达到使用客户端的控件来调用服务器端的函数的--小结
  14. [jQuery]无法获取隐藏元素(display:none)宽度(width)和高度(height)的新解决方案
  15. Django:之不得不说的web框架们
  16. Promise实现多图预加载
  17. HTML表单操作的记录
  18. 为什么内核访问用户数据之前,要做access_ok?【转】
  19. p1110 报表统计(FHQ-TREAP/TREAP)
  20. VS2012 创建的entityframework 4.1版本

热门文章

  1. Python设置
  2. dajngo ORM查询中select_related的作用,博客主题的定制,从数据库中按照年月筛选时间
  3. JS事件流、事件监听、事件对象、事件委托
  4. 7.css3表格、列表、边框的样式设置--list/border
  5. lspci - 列出所有PCI设备
  6. js emoji 过滤
  7. Linux Qt cannot find -lGL错误完美解决方案(亲测有效)
  8. Java web项目搭建系列之二 Jetty下运行项目
  9. 管线命令(Pipe)
  10. Qt带参数的信号和槽