美文网首页
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