当前位置: 移动技术网 > IT编程>开发语言>Java > SpringBoot中ConditionalOnClass注解的原理

SpringBoot中ConditionalOnClass注解的原理

2020年05月12日  | 移动技术网IT编程  | 我要评论

变身后遗证,赛尔号外i挂无毒下载,预报一页通

springboot中的自动配置类有很多conditionalonclass注解,@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注解标记的类加入到

容器中






                    

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网