Java Class冲突定位思路

  JAVA的父类委托加载机制,再带来巨大便利性和效率提升的同时的同时也带来不少麻烦,最直接的就是类冲突造成的问题,以下场景不知道诸位是不是有点熟悉。

本文定义的类冲突定义为相同命名空间下的class分散在不通的jar包之中。

1、造成的注入系统混乱。

2、造成类型判断系统混乱,例如 if ((paramObject instanceof CLASSS))判断失灵

3、不同版本class实现方法有升级 例如Ajar包支持getXX(A,B),而另外jar中却只有getXX(A)

4、在数据在运算中的神秘失踪,如方法A jar中有方法void A(B b),C包中调用A的方法传入的对象 b和Ajar中的B加载的是有类冲突的B。运算结果可以想而知。

这种现象造成的一个问题就是程序员回说我的代码没有问题,我本地也是正常的....,之类的神奇现象,下面尝试去解决一下这几个问题。

1、个人认为首先要对类加载机制有个适当的了解。

以当前比较流行的tomcat为例:加载顺序个人认为讲的比较详细的查阅。

http://www.cnblogs.com/xing901022/p/4574961.html

http://www.ibm.com/developerworks/cn/java/j-lo-classloader/

  2、定位一下我的classpath或者项目中会从那几个路径中加载,然后找出

我的程序到底加载的是哪个呢?

可以用该方法在文件中找出有哪些类有可能造成冲突。

  

import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.io.*;

public class JarFinder {

public static void FindClassInJar(String jarName) throws IOException {

String filePath = jarName;
if (filePath.endsWith(".jar")) {
} else
return;
java.util.jar.JarFile file = new JarFile(filePath);
Enumeration<JarEntry> entrys = file.entries();
while (entrys.hasMoreElements()) {
JarEntry jar = entrys.nextElement();
String tmpJarName = jar.getName();

tmpJarName = tmpJarName.replace(‘/‘, ‘.‘);
if (tmpJarName.contains("javax.mail.Multipart")) {
System.out.println(tmpJarName + " " + file.getName());
}
}
file.close();
}

final static void ShowAllFileInDir(File dir) throws Exception {
File[] fs = dir.listFiles();
for (int i = 0; i < fs.length; i++) {
String file = fs[i].getAbsolutePath();
FindClassInJar(file);
if (fs[i].isDirectory()) {
try {
ShowAllFileInDir(fs[i]);
} catch (Exception e) {
}
}
}
}

public static void main(String[] args) throws Exception {
File root = new File("C:/Program Files/Java/jdk1.8.0_102/jre/lib/ext");

ShowAllFileInDir(root);
}
}

3、减少相关jar包的数量

1、类统一,比如部署在tomcat上的不同项目每个项目多有jar A,那么不妨把jar A放在tomcat的/common/lib目录下。

2、尽量把能去掉的jar从项目中移除出去

此方法通常可以解决一大部分问题,个人认为也是解决这类问题的一个关键思路。

4、代码版本统一

解决问题的最好办法就是预防。部署在同一个tomcat下的项目使用的基础jar包要尽量统一,从制度和规范上解决这个问题。最好能一个公司统一的依赖库,maven是个不错的管理方式,公司按照统一的步调处理依赖项。

5、对于不能移除的可以通过控制jar包加载的顺序

  

6、确认不需要的jar包是否已经真从相关路径中移除。

个人就曾遇到从项目的依赖项中把jar去掉了,但是lib路径下仍存在这个jar导致的仍然被打到包里去了,活活郁闷两天。

其他有可能用到定位class路径的方法:

public static String getProjectPath() {

java.net.URL url = oracle.sql.NCLOB.class.getProtectionDomain().getCodeSource().getLocation();
String filePath = null;
try {
filePath = java.net.URLDecoder.decode(url.getPath(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
if (filePath.endsWith(".jar"))
filePath = filePath.substring(0, filePath.lastIndexOf("/") + 1);
java.io.File file = new java.io.File(filePath);
filePath = file.getPath();
return filePath;
}

public static String getRealPath() {
String realPath = oracle.sql.NCLOB.class.getClassLoader().getResource("").getFile();
//java.io.File file = new java.io.File(realPath);
//realPath = file.();

System.out.println(realPath);
try {
realPath = java.net.URLDecoder.decode(realPath, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}

return realPath;
}

public static String getAppPath(Class<?> cls) {
// 检查用户传入的参数是否为空
if (cls == null)
throw new java.lang.IllegalArgumentException("参数不能为空!");

ClassLoader loader = cls.getClassLoader();
// 获得类的全名,包括包名
String clsName = cls.getName();
// 此处简单判定是否是Java基础类库,防止用户传入JDK内置的类库
if (clsName.startsWith("java.") || clsName.startsWith("javax.")) {
throw new java.lang.IllegalArgumentException("不要传送系统类!");
}
// 将类的class文件全名改为路径形式
String clsPath = clsName.replace(".", "/") + ".class";

System.out.println(clsPath);

// 调用ClassLoader的getResource方法,传入包含路径信息的类文件名
java.net.URL url = loader.getResource(clsPath);
// 从URL对象中获取路径信息
String realPath = url.getPath();
System.out.println(realPath);
// 去掉路径信息中的协议名"file:"
int pos = realPath.indexOf("file:");
if (pos > -1) {
realPath = realPath.substring(pos + 5);
}
//System.out.println(realPath);
// 去掉路径信息最后包含类文件信息的部分,得到类所在的路径
//pos = realPath.indexOf(clsPath);
//realPath = realPath.substring(0, pos - 1);
// 如果类文件被打包到JAR等文件中时,去掉对应的JAR等打包文件名
//if (realPath.endsWith("!")) {
// realPath = realPath.substring(0, realPath.lastIndexOf("/"));
//}
//java.io.File file = new java.io.File(realPath);
//realPath = file.getAbsolutePath();

try {
realPath = java.net.URLDecoder.decode(realPath, "utf-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
return realPath;
}

从问题的两面性来看。这种加载机制也能给我带来便利性的一面。

比如我们要修改jar A中类B的实现,而我们又没有源代码,此时这种加载机制就很有用了。

我们只需要在项目的src中按照B的包名搭建即可。

不过使用此方法时要注意改类影响的范围,尽量不要在通用的类上执行此操作,否则会造成一些不可控的风险。

时间: 2024-08-24 05:14:46

Java Class冲突定位思路的相关文章

Java性能问题定位 - 基础篇

一句话总结:从问题现象为入口,归结为3类问题进行定位分析:内存满.CPU高.线程阻塞. 首先先介绍下jvisualvm这款jdk自带的性能工具.通常我们要定位哪块代码性能差,耗时久,最原始的办法就是在各个方法前后日志打印时间戳并计算耗时,这种方法很繁琐,通常要加很多日志多次部署才能定位到,我一开始也是这么搞的.而使用jvisualvm工具则可以直接查看整个业务代码调用链中各个方法的耗时及占比,直接就能定界出是哪个方法性能差,耗时久. 操作步骤:点击抽样器页签,点击CPU抽样,前台操作触发代码执行

【转】java性能测试 问题定位

性能测试的概念是什么,基本目的是什么,我想大家都基本清楚,不作详述,总之,性能测试只是测试过程中的一种方式,帮助我们的功能更好的运行,如果功能测试是可用,易用,满足需求.用户使用为目的,性能测试无非就是让这些目的更流畅.没有什么专业的概念,无非实现两个字:好用!所以,性能测试这种测试方式在发生过程中,其中一个过渡性的工作,就是对执行过程中的问题,进行定位,对功能的定位,对负载的定位,最重要的,当然就是问题中说的“瓶颈”,接触性能测试不深,更非专家,自己的理解,瓶颈产生在以下几方面: 1.网络瓶颈

java 包冲突解决方法

1.诊断包冲突 java.lang.NoSuchMethodError: org.apache.commons.io.output.DeferredFileOutputStream.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/io/File;)V 2.解决 2.1 可见的依赖冲突 在eclipse中打开工程,在pom文件的dependency hierarchy中,搜冲突的包commons-io,查看各依赖包的依赖信息.包有依赖冲突的话,

PHP微信公众平台跳转网页实现定位思路 By:阿尚

这两天做微信公众平台的时候遇到一个进入网页进行用户定位的功能,由于各方面原因,没有去使用微信提供的js定位.以前也没做过微信相关的开发-加之微信官方提供的API文档着实看着蛋疼,苦思无果,终于在第三天某位高人提了一点思路,哥顿时就茅塞顿开了! 话不多说,先上需求! 需求:类似美团外卖,进入公众平台以后点击订餐跳到网页直接定位加载数据! 实现框架:ThinkPHP 思路: 1.到微信开发者中心开启用户地理位置上报功能,实现每次用户进入公众号微信上报当前用户的地理位置到服务器. 2.服务器接收微信上

Java Map底层实现思路

package cn.com.commsoft.map; public class MyMap { MyEntry[] arr = new MyEntry[100]; int size; /** * 采用hash算法实现map,(每个对象都有一个地址, * 根据地址生成的一个hash码,由于每个对象的地址都不一样,所以 * 生成的hash码是唯一的) * @param key * @param value */ public void put(Object key, Object value){

WINDOWS 64位SSDT定位思路

在32位Windows中我们有很多定位SSDT的方法,最直接的就是利用导出符号来找到SSDT.再有就是通过在nt!KeAddSystemServiceTable函数中进行反汇编搜索.可是在64位WINDOWS中这两种方法都行不通.在64位Windows中不在导出SSDT了,同时nt!KeAddSystemServiceTable中也不再出SSDT了(此处说明有误,应该为不出现直接的SSDT地址了,个人水平有限感觉计算太麻烦.).这样要HOOK SSDT表就出现了第一个问题如何找到它?我想了三种思

java+selenium元素定位和元素操作

1.元素定位 ID定位元素: findElement(By.id("")); 通过元素的名称定位元素: findElement(By.name("")); 通过元素的html中的位置定位元素: findElement(By.xpath("")); 通过元素的标签名称定位元素: findElement(By.tagName("")); 通过元素的链接名称定位元素: findElement(By.linkText("&q

Linux环境下Java应用性能分析定位-CPU使用篇

1     CPU热点分析定位背景 CPU资源还是很昂贵的,为了深刻感受到这种昂贵,间下图当前CPU的资源售价: 所以对于程序猿们来说,需要让程序合理高效的使用CPU资源.利用有限的CPU资源来解决完成我们面对的实际问题,这就是为什么我们要尽可能优化程序. 不篇从微观层面展开介绍说明,不做宏观层面的介绍(譬如数据中心级容量监控,管理调度(OpenStack,Kubernates等)以及迁移(手动,自动,冷迁,热迁)). 本篇将以倒推式方法组织目录结构.出现了问题怎么办,以及为什么要这样做,以及后

CPU100%问题快速定位思路

在我日常运维工作中,无论自己 或同事.朋友总会问我,服务器CPU使用率100%,卡死了,这样的话,那今天咱们就一起模拟故障,进行细致的分析,首先介绍下,CPU出现问题的几种原因: 一.CPU 100%问题定位 1.功能问题,通过日志,单步调试相对比较好定位. 2.性能问题,例如线上服务器CPU100%,如何找到相关服务,如何定位问题代码,更考验技术人的功底. 2018-6-4 今日在公司进行一次线上服务CPU问题排查实战演练,公司全体同事反馈有收获,特将故障演练报告分享出来,希望对大家也有帮助.