美文网首页
ConditionalOnClass实现原理

ConditionalOnClass实现原理

作者: 十毛tenmao | 来源:发表于2021-06-10 13:52 被阅读0次

Spring Boot实现了很多有用的条件注入,其中ConditionalOnClass的实现让人感到困惑,因为如果类不存在的话,加载就会抛出错误NoClassDefFoundError。其实Spring Boot使用的字节码技术来实现这一点的

实现原理

Spring在加载类之前,会提前使用字节码技术来读取这个类(并没有使用ClassLoader),然后解析里面的ConditionalOnClass,再在classpath下找到对应的类,如果找到就注入,否则就不注入

最终是否满条件的逻辑

  • 匹配的方法:SpringBootCondition#matches(ConditionContext, AnnotatedTypeMetadata)

其中AnnotatedTypeMetadata就会通过字节码技术解析得到的注解信息,可以通过断点的方式,可以跟踪注解信息是如何从字节码解析得到的

@Override
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    String classOrMethodName = getClassOrMethodName(metadata);
    try {
        ConditionOutcome outcome = getMatchOutcome(context, metadata);
        logOutcome(classOrMethodName, outcome);
        recordEvaluation(context, classOrMethodName, outcome);
        return outcome.isMatch();
    }
    catch (NoClassDefFoundError ex) {
        throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to "
                + ex.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)", ex);
    }
    catch (RuntimeException ex) {
        throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
    }
}

关键路径

通过跟踪Spring解析流程,可以得到以下字节码解析类信息的路径如下。

public static void main(String[] args) throws Exception {
    FileSystemResource resource = new FileSystemResource("/Users/tenmao/Workspace/boot/tenmao-cond/target/classes/com/tenmao/cond/UserManager.class");
    //元数据解析器工厂
    CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
    //元数据解析器
    MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
    //解析出来的类元数据
    ClassMetadata classMetadata = metadataReader.getClassMetadata();
    System.out.println(classMetadata);
}

注意:整个过程程序并没有使用ClassLoader加载UserManager

参考

相关文章

网友评论

      本文标题:ConditionalOnClass实现原理

      本文链接:https://www.haomeiwen.com/subject/jbiueltx.html