zoukankan      html  css  js  c++  java
  • 记一次SpringContextHolder.getBean出现异常NoClassDefFoundError: Could not initialize class

    代码如下:

    public class TestUtils {
        private static UserDao logDao = SpringContextHolder.getBean(UserDao.class);
        
        public static String getLog(String type){
            return "!23";
        }
    }

    在controller中使用这Utils的时候出现如下错误:

    奇怪的是在容器中又能得到UserDao,为何初始化这个TestUtils的时候就失败了呢。

    经过一番排查,发现项目启动的时候有这么一段日志

    2019-10-29 15:36:22.839  WARN 21948 --- [           main] o.mybatis.spring.SqlSessionFactoryBean   : Cannot load the 'file [D:*utilsTestUtils.class]'. Cause by java.lang.NoClassDefFoundError: Could not initialize class com.*.utils.TestUtils

    所以觉得是mybatis的问题,mybaits在扫描所有entity的时候逻辑(mybatis-spring-boot-starter是2.1.1对应的mybatis-spring的版本2.0.3)

        if (hasLength(this.typeAliasesPackage)) {
          scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
              .filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
              .filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
        }
    
    
      private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType) throws IOException {
        Set<Class<?>> classes = new HashSet<>();
        String[] packagePatternArray = tokenizeToStringArray(packagePatterns,
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        for (String packagePattern : packagePatternArray) {
    //会先扫描出所有typeAliasesPackage下面所有的类 Resource[] resources
    = RESOURCE_PATTERN_RESOLVER.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class"); for (Resource resource : resources) { try { ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
    //此时会先加载这个类,加载类的时候里面的静态属性会初始化,但是此时容器中还有UserDao的Bean实例,所以导致初始化失败,触发异常 Class
    <?> clazz = Resources.classForName(classMetadata.getClassName());
    //此时才判断superType
    if (assignableType == null || assignableType.isAssignableFrom(clazz)) { classes.add(clazz); } } catch (Throwable e) { LOGGER.warn(() -> "Cannot load the '" + resource + "'. Cause by " + e.toString()); } } } return classes; }

    上面就是导致出现问题的原因。

    看了一下之前的项目,逻辑一样,但为啥没出现问题呢,发现之前项目引用的mybatis-spring-boot-starter是1.3.2版本,对应的mybatis-spring的版本的1.3.2。

    那么里面的实现是怎么样呢?为何没出现类似的错误呢?

    if (hasLength(this.typeAliasesPackage)) {
        String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        for (String packageToScan : typeAliasPackageArray) {
            configuration.getTypeAliasRegistry().registerAliases(packageToScan,
                    typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
            }
        }
    }
    
    public void registerAliases(String packageName, Class<?> superType){
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
        //会先过滤superType
        resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
        Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
        for(Class<?> type : typeSet){
          // Ignore inner classes and interfaces (including package-info.java)
          // Skip also inner classes. See issue #6
          if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
            registerAlias(type);
          }
        }
    }

    两个解决办法:

    1.降低mybatis-spring-boot-starter 的版本到(经测试mybatis-spring.jar的2.0.0及以下版本都可以,其他版本没看源码)

    2.精确指定到entity的目录(建议此,减少扫描和遍历的次数)

  • 相关阅读:
    vijos1194 Domino
    vijos1603迷宫
    怎样实现App安装来源追踪
    怎样实现App安装来源追踪
    怎么在Chrome和Firefox浏览器中清除HSTS设置?
    怎么在Chrome和Firefox浏览器中清除HSTS设置?
    element UI排坑记(一):判断tabs组件是否切换
    ZooKeeper分布式锁的实现原理
    ZooKeeper分布式锁的实现原理
    TensorFlow框架 入门笔记
  • 原文地址:https://www.cnblogs.com/gavinYang/p/11759448.html
Copyright © 2011-2022 走看看