关于Spring4 的@profile注解
源码如下:
可以发现,@Profile注解其实是实现了Conditional注解,且传入的实例为ProfileCondition。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({ProfileCondition.class})
public @interface Profile {
String[] value();
}
继续前进,进入ProfileCondition.class,源码如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context.annotation;
import java.util.Iterator;
import java.util.List;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.MultiValueMap;
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;
}
}
很明显,该类实现了Condition接口。
首先:通过getAllAnnotationAttributes(Profile.class.getName());获取到了用于@Profile注解的所有属性,那么到底属性指的是什么,通过断点查看下
结果发现,返回的Map中,值是proflie的名称的一个集合(@Profile【({"dev", "asd","ggg"})】
有了值以后,那么就要开始检查以该值为名称的profile到底有没有激活。
首先 进入一遍循环,把profile的第一个值放入value【可以看出,value是一个String[3] 的 数组】
接着,通过Environment的acceptsProfiles方法。该方法用于验证profile是否激活,激活则返回true。acceptsProfiles源码如下
public boolean acceptsProfiles(String... profiles) {
//先通过断言判断是否为空
Assert.notEmpty(profiles, "Must specify at least one profile");
String[] var2 = profiles;
int var3 = profiles.length;
//开始循环整个数组,对每一个profiles内的值进行判断
for(int var4 = 0; var4 < var3; ++var4) {
String profile = var2[var4];
//StringUtils.hasLength(profile)判断profile是否为空
if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') {
if (!this.isProfileActive(profile.substring(1))) {
return true;
}
} else if (this.isProfileActive(profile)) {
return true;
}
}
return false;
}
通过acceptsProfiles可以看出,只要有一个profile满足激活,那么就可以返回true。
但是注意:整条语句前加了!
也就是说,当前的profile 为激活时,while中的表达式整体就是false,不再进入循环,执行下一条语句,也就是true。matches返回true的话,bean也就可以被创建。
如果,当前的profile未激活,while中的表达式整体就是true,再次进入循环,判断下一组profile名称是否被激活,一直循环,当所有的profile 名称都被循环了一遍还没有跳出循环,那么说明所有的profile都没被激活,通过
if (!var4.hasNext()) {return false;}
返回flase,无法为该@Profile注释的bean创建。
这就是整个@Profile借助@Conditional来实现创建bean的原理