SpringBoot中ConditionalOnClass注解的原理
springboot中的自动配置类有很多conditionalonclass注解,
那这些conditionalonclass注解的原理是什么呢,了解conditionalonclass注解的原理前要先了解condition注解的原理,因为condition注解是最基础的
@target({elementtype.type, elementtype.method}) @retention(retentionpolicy.runtime) @documented public @interface conditional { class<? extends condition>[] value(); }
contional注解里可以标注的属性是一个class数组
而处理这个注解的是一个condition接口,springbootcondition就实现了这个接口来对contional注解进行处理
@functionalinterface public interface condition { boolean matches(conditioncontext var1, annotatedtypemetadata var2); }
public final boolean matches(conditioncontext context, annotatedtypemetadata metadata) {
string classormethodname = getclassormethodname(metadata);
try {
//获取contionoutcome对象,这个对象的属性是是否匹配和匹配信息
conditionoutcome outcome = this.getmatchoutcome(context, metadata);//getmatchoutcome方法在本类是一个抽象方法,具体实现是在子类实现的,oncontionalclass就实现了这个方法
this.logoutcome(classormethodname, outcome);
this.recordevaluation(context, classormethodname, outcome);
return outcome.ismatch();//返回匹配结果 true或者是false
} catch (noclassdeffounderror var5) {
throw new illegalstateexception("could not evaluate condition on " + classormethodname + " due to " + var5.getmessage() + " not found. make sure your own configuration does not rely on that class. this can also happen if you are @componentscanning a springframework package (e.g. if you put a @componentscan in the default package by mistake)", var5);
} catch (runtimeexception var6) {
throw new illegalstateexception("error processing condition on " + this.getname(metadata), var6);
}
}
了解了condition注解的原理之后就可以来了解conditionalonclass注解的原理了,可以先看下conditionalonclass注解的定义
@target({elementtype.type, elementtype.method}) @retention(retentionpolicy.runtime) @documented @conditional({onclasscondition.class}) public @interface conditionalonclass { class<?>[] value() default {}; string[] name() default {}; }
可以看到conditionalonclass注解其实是通过conditional注解起作用的,conditional注解标注的属性是onclasscondition.class,接着来看onclasscondition.class的源码,从源码可以看到onclasscondition.class是通过getmatchoutcome来获取匹配结果的,
而匹配结果是在springbootcondition里被使用的
public conditionoutcome getmatchoutcome(conditioncontext context, annotatedtypemetadata metadata) { //获取容器的类加载器 classloader classloader = context.getclassloader(); conditionmessage matchmessage = conditionmessage.empty(); // 获取@conditionalonclass注解 value以及name属性声明的所有类 list<string> onclasses = this.getcandidates(metadata, conditionalonclass.class); list onmissingclasses; if (onclasses != null) { //加载conditionalonclass注解指定的类 onmissingclasses = this.filter(onclasses, classnamefilter.missing, classloader); // 如果加载成功即类路径上有conditionalonclasses注解指定的类,也就是说onmissingclasses为空,加载失败即onmissingclasses不为空,返回一个匹配失败的结果 if (!onmissingclasses.isempty()) { return conditionoutcome.nomatch(conditionmessage.forcondition(conditionalonclass.class, new object[0]).didnotfind("required class", "required classes").items(style.quote, onmissingclasses)); } matchmessage = matchmessage.andcondition(conditionalonclass.class, new object[0]).found("required class", "required classes").items(style.quote, this.filter(onclasses, classnamefilter.present, classloader)); } onmissingclasses = this.getcandidates(metadata, conditionalonmissingclass.class); if (onmissingclasses != null) { //加载conditionalonmissingclass注解指定的类 list<string> present = this.filter(onmissingclasses, classnamefilter.present, classloader); // 如果加载失败present为空,加载成功即present不为空,返回一个匹配失败的结果 if (!present.isempty()) { return conditionoutcome.nomatch(conditionmessage.forcondition(conditionalonmissingclass.class, new object[0]).found("unwanted class", "unwanted classes").items(style.quote, present)); } matchmessage = matchmessage.andcondition(conditionalonmissingclass.class, new object[0]).didnotfind("unwanted class", "unwanted classes").items(style.quote, this.filter(onmissingclasses, classnamefilter.missing, classloader)); } return conditionoutcome.match(matchmessage);//返回匹配结果 }
public final boolean matches(conditioncontext context, annotatedtypemetadata metadata) {
string classormethodname = getclassormethodname(metadata);
try {
conditionoutcome outcome = this.getmatchoutcome(context, metadata);//上面方法返回的匹配结果是在这里使用的
this.logoutcome(classormethodname, outcome);
this.recordevaluation(context, classormethodname, outcome);
return outcome.ismatch();//匹配成功则返回true,把conditionalonclass标记的类加入容器中,匹配失败则跳过标注的类
} catch (noclassdeffounderror var5) {
throw new illegalstateexception("could not evaluate condition on " + classormethodname + " due to " + var5.getmessage() + " not found. make sure your own configuration does not rely on that class. this can also happen if you are @componentscanning a springframework package (e.g. if you put a @componentscan in the default package by mistake)", var5);
} catch (runtimeexception var6) {
throw new illegalstateexception("error processing condition on " + this.getname(metadata), var6);
}
}
可以看出getmatchoutcome方法里是通过filter方法来判断类路径上是否有conditionalonclass注解里标注的类
protected final list<string> filter(collection<string> classnames, filteringspringbootcondition.classnamefilter classnamefilter, classloader classloader) { if (collectionutils.isempty(classnames)) { return collections.emptylist(); } else { list<string> matches = new arraylist(classnames.size()); iterator var5 = classnames.iterator(); while(var5.hasnext()) { string candidate = (string)var5.next(); //classnamefilter为missing时,如果加载到了类路径中 //conditionalonclass指定的类,则matches的返回值为flase,则不会把conditionalonclass注解的属性加入到matches,即matches为空 if (classnamefilter.matches(candidate, classloader)) { matches.add(candidate); } } return matches; } }
filter方法是通过classnamefilter这个枚举类里的matches方法来判断类路径上是否有conditionalonclass注解里标注的类
protected static enum classnamefilter { //返回类路径中是否存在该类,该类能被加载则返回true,否则返回false present { public boolean matches(string classname, classloader classloader) { return ispresent(classname, classloader); } }, //返回类路径中是否不存在该类,该类能被加载则返回false,否则返回true missing { public boolean matches(string classname, classloader classloader) { return !ispresent(classname, classloader); } }; private classnamefilter() { } abstract boolean matches(string var1, classloader var2); static boolean ispresent(string classname, classloader classloader) { if (classloader == null) { classloader = classutils.getdefaultclassloader(); } try { //利用loadclass以及forname 方法,判断类路径下有没有这个指定的类 //有则返回true filteringspringbootcondition.resolve(classname, classloader); return true; } catch (throwable var3) { //没有则加载失败返回false return false; } } } }
protected static class<?> resolve(string classname, classloader classloader) throws classnotfoundexception {
return classloader != null ? classloader.loadclass(classname) : class.forname(classname);//有类加载器就通过类加载器加载,没有则通过forname方法加载
}
看到这里我们就可以知道conditionalonclass注解里的类属性是通过类加载器和forname的方法判断类路径上是否有该类,如果类路径上有该类则加载成功,也就是能够成功匹配,成功匹配后springboot就会把conditionalonclass注解标记的类加入到
容器中
上一篇: linux定时任务基础命令介绍(14)
下一篇: linux中Jetty的安装和配置方法