at java.net.URLClassLoader.findClass(URLClassLoader.java:382) 问题排查

一、问题的提出

之前写的框架类都没有打成jar包,无论是在idea环境还是在真实运行环境,都运行正常。后来把项目改成了maven项目,一个项目里许多模块,框架打包以后在idea运行正常,但是在真实环境下,就提示没有找到类,只要是包外的类都找不到。提示 java.lang.ClassNotFoundException,at java.net.URLClassLoader.findClass(URLClassLoader.java:382) 。

   真实环境运行命令是   :

 java   -classpath D:\cncapp\WEB-INF\classes -Djava.ext.dirs=D:\cncapp\WEB-INF\lib cn.tianlong.java.application.startadmin 

其中 -classpath 定义了包外的应用类的目录 

-Djava.ext.dirs   定义了引用包的目录,因为引用的包比较多,都统一放在一个目录下,包括我自己框架的各个包。

cn.tianlong.java.application.startadmin ——为启动的类。

执行后,除了在运行命令中明确指定的启动类可以运行,其他的类都无法找到。

二、问题的原因

通过网上各种资料查询,最后终于弄清了。

我的框架项目中,所有的类通过一个工厂类统一实例化,利用类的反射的机制。具体的代码是:

Class.forName(className),className是要启动类的全名。

之前用这个代码没有出现问题,为何打包后出现问题了呢?主要是以下两个问题没有搞清。

1、Class.forName(className)  这个方法的类加载器问题。这个方法的加载器是加载调用类的加载器,也就是说,如果A对象执行这个方法,那么加载器就是之前加载A的加载器。这个方法其实是个简化实现,具体内容如下:

public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

可以看出,具体代码是 forName0(className, true, ClassLoader.getClassLoader(caller), caller)。这个方法里面默认是当前对象的加载器。

2、java命令行的加载器问题。

    在运行命令  java   -classpath D:\cncapp\WEB-INF\classes -Djava.ext.dirs=  中,

 -classpath  定义的路径或者jar包,加载时用的是系统或应用程序加载器AppClassLoader。

而 -Djava.ext.dirs 定义的路径下面的包,加载时用的是扩展类加载器ExtClassLoader。

那么问题怎么产生的呢? 在我的框架里所有的类用一个工厂类实例化,没有打包之前,这个工厂类和其他类都放在-classpath 目录下,那么用的都是应用程序加载器AppClassLoader,没有出现问题。当把框架的类打包后放在Djava.ext.dirs 目录下后,那么加载器变成了扩展类加载器ExtClassLoader。这时候在用Class.forName(className)方法去加载类的时候,自然用扩展类加载器去加载了,也就无法加载-classpath目录下的类。在idea环境运行时,它把所有的包放在-classpath 下,而没有用-Djava.ext.dirs 指定目录,所以idea运行时正常的。

三、问题的解决

     搞清问题的原因后,那么解决就比较简单了,就是不要简单的用forName(String className),为了适应各种情况, 稍微增加了代码,具体如下:

public  Class<?> myClassforName(String className){Class<?> cls = null; // 取得Class对象try {cls = Class.forName(className);} catch (ClassNotFoundException e){ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();try {cls=Class.forName(className,true,systemClassLoader) ;} catch (ClassNotFoundException e1) {e1.printStackTrace();String log= "classPath:"+classPath +"\n"+className + ": 没有找到类文件\n"+TLToolsUtils.exceptionToString(e1) ;putLog(log, LogLevel.ERROR, "myClassforName");}}return  cls;
}

   定义了自己的myClassforName方法,实现中,如果Class.forName(className) 没有找到类,那么获得系统加载器,用指定加载器的Class.forName(className,true,systemClassLoader)进一步的实例化。这样保证了-classpath 下的类肯定能实例化。更改代码后,问题解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/241938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springcloud-gateway-2-鉴权

目录 一、跨域安全设置 二、GlobalFilter实现全局的过滤与拦截。 三、GatewayFilter单个服务过滤器 1、原理-官方内置过滤器 2、自定义过滤器-TokenAuthGatewayFilterFactory 3、完善TokenAuthGatewayFilterFactory的功能 4、每一个服务编写一个或多个过滤器&#xff0c…

关于“Python”的核心知识点整理大全39

目录 ​编辑 14.1.5 将 Play 按钮切换到非活动状态 game_functions.py 14.1.6 隐藏光标 game_functions.py game_functions.py 14.2 提高等级 14.2.1 修改速度设置 settings.py settings.py settings.py game_functions.py 14.2.2 重置速度 game_functions.py 1…

DPDK系列之四十硬件加速和功能卸载

一、硬件卸载 硬件加速&#xff0c;听名字就是明白是利用硬件加速。不太准确&#xff0c;硬件加速其实更有效进行硬件的分工&#xff0c;通过分工实现硬件的整体的效率的提升。其实硬件卸载就是硬件加速&#xff0c;而实现硬件加速就需要进行功能卸载&#xff0c;整体上就可以…

饥荒Mod 开发(二一):超大便携背包,超大物品栏,永久保鲜

饥荒Mod 开发(二十)&#xff1a;显示打怪伤害值 源码 游戏中的物品栏容量实在太小了&#xff0c;虽然可以放在箱子里面但是真的很不方便&#xff0c;外出一趟不容易看到东西都不能捡。实在是虐心。 游戏中的食物还有变质机制&#xff0c;时间长了就不能吃了&#xff0c;玩这个游…

【高数定积分求解旋转体体积】 —— (上)高等数学|定积分|柱壳法|学习技巧

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 Shell method Setting up the Integral 例题 Example 1: Example 2: Example 3: Computing…

Pytorch学习笔记 | GAN生成对抗网络 | 代码 | 生成mnist手写数字图片

文章目录 GAN网络简介测试判别器和测试生成器测试判别器测试生成器首次生成图片(效果欠佳)生成图片(比较清晰,但还有差距)生成图片(继续优化,输入扩维)生成图片(继续优化,)GAN网络简介 生成对抗网络(GAN,Generative Adversarial Networks)是一种深度学习模型,由…

Linux--shell练习题

1、写一个 bash脚本以输出数字 0 到 100 中 7 的倍数(0 7 14 21...)的命令。 vim /shell/homework1.sh #!/bin/bash for num in {0..100} doif [[ num%7 -eq o ]];thenecho $numfi done执行输出脚本查看输出结果 输出结果&#xff1a; 2、写一个 bash脚本以统计一个文本文件…

LLM之RAG实战(七)| 使用llama_index实现多模态RAG

一、多模态RAG OpenAI开发日上最令人兴奋的发布之一是GPT-4V API&#xff08;https://platform.openai.com/docs/guides/vision&#xff09;的发布。GPT-4V是一个多模态模型&#xff0c;可以接收文本/图像&#xff0c;并可以输出文本响应。最近还有一些其他的多模态模型&#x…

flutter 实战 之 dio小实践

我们要对dio进行封装 class HttpRequest {static Future request(String url,{String method "get",Map<String,dynamic>? params})async{// 创建dio实例BaseOptions baseOptions BaseOptions(baseUrl: base_url,connectTimeout: Duration(seconds: 1));fi…

50 个具有挑战性的概率问题 [04/50]:尝试直至首次成功

一、说明 你好&#xff0c;我最近对与概率相关的问题产生了兴趣。我偶然发现了 Frederick Mosteller 所著的《五十个具有挑战性的概率问题及其解决方案》这本书。我认为创建一个系列来讨论这些可能作为面试问题出现的迷人问题会很有趣。每篇文章仅包含 1 个问题&#xff0c;使其…

【四】【C语言\动态规划】地下城游戏、按摩师、打家劫舍 II,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…

一款超好看流行的HTML随机视频播放背景引导页面源码

前言 今天宋佳乐博客给大家带来一款2024新版视频背景网址导航引导页面源码带背景动态HTML源码 源码介绍 2024新版视频背景网址导航引导页面源码带背景动态HTML源码&#xff0c;非常的炫酷&#xff0c;有需要的自行去体验吧&#xff0c;还是非常不错的 演示地址&#xff1a;点…

《xHCI 1.2》3体系结构概览

3.2 xHCI数据结构 3.2.1 Device Context Base Address Array 3.2.2 Device Context 3.2.3 Slot Context

keystone和beaengine的编译

编译Keystone 根据github的文档编译不出来&#xff0c;所以还是用CMake项目转成Visual Studio的项目来编译 1、下载源码 https://github.com/keystone-engine/keystone clone或者直接下载zip都行 2、CMake创建Visual Studio项目 下载和安装CMake就不细说了&#xff0c;在…

《妙趣横生的算法》(C语言实现)-第2章 常用的查找与排序方法

【实例2-1】一个结构体数组中存放的是学生记录&#xff0c;每条记录包括&#xff1a;学号、姓名、成绩。编写一个程序&#xff0c;要求输出1001编号同学的具体信息。 // 2-1 2023年12月23日18点05分-18点14分 typedef struct student{ // 定义学生结构体类型 int id; // 学生…

网络7层架构

网络 7 层架构 什么是OSI七层模型&#xff1f; OSI模型用于定义并理解数据从一台计算机转移到另一台计算机&#xff0c;在最基本的形式中&#xff0c;两台计算机通过网线和连接器相互连接&#xff0c;在网卡的帮助下共享数据&#xff0c;形成一个网络&#xff0c;但是一台计算…

正餐---二叉树的OJ题

目录​​​​​​​ 前言&#x1f36f; 1. 检查两颗树是否相同&#x1f947; 1.1 思路分析&#x1fa99; 1.2 代码实现&#x1f9f0; 2. 单值二叉树&#x1f332; 2.1 思路分析&#x1f52e; 2.2 代码实现&#x1f488; 3. 二叉树的前序遍历&#x1f39f;️ 3.1 思路分…

【数据结构】线性表

一.线性表 1.定义&#xff1a; n个同类型数据元素的有限序列&#xff0c;记为 L为表名&#xff0c;i为数据元素在线性表中的位序&#xff0c;n为线性表的表长&#xff0c;n0时称为空表。 2.数据元素之间的关系&#xff1a; 直接前驱和直接后继 3.抽象数据类型线性表的定义…

SQL进阶:多表查询

在SQL基础部分,我们在讲解的过程中只用到了单表查询。但实际上,常见的业务场景单表查询不能满足,或者拆分查询性能过慢。这个时候我们就需要用到连接查询。即查询多表按一定规则合并后的数据。 注意,合并后的数据也是表,也有列的概念,只不过一般存储在内存中。 由于集合…

jQuery 实现带手柄自由调整页面大小的功能

在https://blog.csdn.net/qq_44327851/article/details/135006421文章中提到了用纯JavaScript实现自由调整页面大小的功能&#xff0c;其中有基础版和优化版&#xff0c;优化版通过添加手柄解决了基础版在调整页面大小的时候不够灵活的问题&#xff0c;其实解决不够灵活的问题还…