Spring中的@conditional註解
阿新 • • 發佈:2019-04-27
gist names auth als context cond load ica 2018年
今天主要從以下幾方面來介紹一下@Conditional註解
-
@Conditional註解是什麽
-
@Conditional註解怎麽使用
1,@Conditional註解是什麽
@Conditional註解是可以根據一些自定義的條件動態的選擇是否加載該bean到springIOC容器中去,如果看過springBoot源碼的同學會發現,springBoot中大量使用了該註解
2,@Conditional註解怎麽使用
查看@Conditional源碼你會發現它既可以作用在方法上,同時也可以作用在類上,源碼如下:
@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(); }
設置給@conditional的類需要實現Condition接口
我們看一下Condition的源碼:
public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); } ConditionContext源碼: public interface ConditionContext { BeanDefinitionRegistry getRegistry(); ConfigurableListableBeanFactory getBeanFactory(); Environment getEnvironment(); ResourceLoader getResourceLoader(); ClassLoader getClassLoader(); } AnnotatedTypeMetadata源碼: 此類能夠讓我們檢查帶有@Bean註解的方法上還有其他什麽註解 public interface AnnotatedTypeMetadata { boolean isAnnotated(String var1); Map<String, Object> getAnnotationAttributes(String var1); Map<String, Object> getAnnotationAttributes(String var1, boolean var2); MultiValueMap<String, Object> getAllAnnotationAttributes(String var1); MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2); }
a,@Conditional作用在方法上
定義一個Condition如下:
/** * 定義一個bean的Condition * * @author zhangqh * @date 2018年5月1日 */ public class MyCondition implements Condition { public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata) { Environment env = context.getEnvironment(); String system = env.getProperty("os.name"); System.out.println("系統環境為 ==="+system); // 系統環境在Windows才加載該bean到容器中 if(system.contains("Windows")){ return true; } return false; } }
定義一個bean加上@Conditional註解如下:
@Conditional({MyCondition.class})
@Bean(value="user1")
public User getUser1(){
System.out.println("創建user1實例");
return new User("李四",26);
}
測試如下:
AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanNames = applicationContext2.getBeanDefinitionNames();
for(int i=0;i<beanNames.length;i++){
System.out.println("bean名稱為==="+beanNames[i]);
}
運行結果:
bean名稱為===mainConfig
bean名稱為===user0
bean名稱為===user1
我這邊電腦系統是window所以user1實例是有創建出來的,如果把MyCondition中的判斷改成if(system.contains("linux"))那麽user1是不會加載到spring容器中的
b,@Conditional作用在類上
修改註解配置如下:
/**
* 定義一個註解配置文件 必須要加上@Configuration註解
*
* @author zhangqh
* @date 2018年4月30日
*/
@Conditional({MyCondition.class})
@Configuration
public class MainConfig {
/**
* 定義一個bean對象
* @return
*/
@Scope
@Lazy
@Bean(value="user0")
public User getUser(){
System.out.println("創建user實例");
return new User("張三",26);
}
//@Conditional({MyCondition.class})
@Bean(value="user1")
public User getUser1(){
System.out.println("創建user1實例");
return new User("李四",26);
}
}
運行測試:
bean名稱為===mainConfig
bean名稱為===user0
bean名稱為===user1
MainConfig中的bean都成功打印出來了,因為我MyCondition條件返回的是true,同樣如果我修改成if(system.contains("linux"))那麽MainConfig的bean就都不會實例化了
c, @profile註解分析
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional({ProfileCondition.class}) public @interface Profile { String[] value(); }
註意:@Profile本身也使用了@Condition註解,並且引用ProfileCondition作為Condition的實現。
以下為ProfileCondition的實現
class ProfileCondition implements Condition {
ProfileCondition() {
}
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
Iterator var4 = ((List)attrs.get("value")).iterator();
Object value;
do {
if (!var4.hasNext()) {
return false;
}
value = var4.next();
} while(!context.getEnvironment().acceptsProfiles((String[])((String[])value)));
return true;
}
}
return true;
}
}
Spring中的@conditional註解