解释这有点棘手.我有一个A类:
public class A { private Integer a1; private Integer a2; // getters and setters. }
有一个静态类B返回我的类A:
public static class B { public static A getCurrentA() { return a; } }
我需要找到B返回的所有A类用法.所以让我们说C级呼叫c.setA(B.getCurrentA())
,然后再进一步调用c.getA().getA2();
,我想找到所有这些.
在真实场景中,我有217个不同的类调用B.getCurrentA()
.我不能手动跟踪Eclipse中的所有调用,并找出调用哪些方法.
Eclipse调用层次结构视图仅向我显示所有调用B.getCurrentA()
.
我怎样才能做到这一点?
编辑
克里斯海耶斯明白我想做什么.为了在不破坏整个系统的情况下重构一些非常糟糕的遗留代码,我需要首先使用Hibernate的投影微调一些查询(系统中的每个映射实体都被急切加载,并且许多实体是相关的,因此一些查询需要很长时间时间取出一切).但首先我需要找到使用哪些属性,以便我不会在某处获得NullPointerException ...
这是我手动做的一个例子:
使用Eclipse的搜索查找对B.getCurrentA()的所有调用;
打开找到的第一个方法,让我们说它是下面的方法:
public class CController { C c = new C(); CFacade facade = new CFacade(); ListCs = new ArrayList (); public void getAllCs() { c.setA(B.getCurrentA()); // found it! facade.search(c); } }
在CFacade类中打开搜索方法:
public class CFacade { CBusinessObject cBo = new CBusinessObject(); public Listsearch(C c) { // doing stuff... cBo.verifyA(c); cBo.search(c); // yes, the system is that complicated } }
打开CBusinessObject类中的verifyA方法并标识使用的字段a2:
public class CBusinessObject { public void verifyA(c) { if (Integer.valueOf(1).equals(c.getA().getA2())) { // do stuff else { // something else } } }
接下来的216场比赛重复步骤2-4 ......耶.
请帮忙.
如果要更改/重构任何源代码,则必须手动查找所有用法并应用代码更改;
无论如何,我有两种不同的方法
静态搜索你可以简单地Text Search
在eclipse中找到它的出现getA2()
.它将直接带你到Caller方法(这里是CBusinessObject.verifyA()) - 但是它会给你每个getA2()的出现,可能来自不同的类
运行时搜索用于java instrumentation API
在运行时更改所需方法的字节代码以查找调用类并运行为java agent
- 使您能够识别调用者而不触及现有代码库,并且非常有用,尤其是当您无法访问源代码时码.
在这里,您将了解如何实施
步骤1-编写代理主类以启动检测
public class BasicAgent { public static void premain(String agentArguments, Instrumentation instrumentation){ System.out.println("Simple Agent"); FindUsageTransformer transformer = new FindUsageTransformer (); instrumentation.addTransformer(transformer,true); } }
第2步 - 编写ClassFileTransformer实现并捕获该方法
public class FindUsageTransformer implements ClassFileTransformer{ Class clazz = null; public byte[] transform(ClassLoader loader,String className,Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if(className.equals("A")){ doClass(className, classBeingRedefined, classfileBuffer); } return classfileBuffer; } private byte[] doClass(String name, Class clazz, byte[] b) { ClassPool pool = ClassPool.getDefault(); CtClass cl = null; try { cl = pool.makeClass(new java.io.ByteArrayInputStream(b)); CtMethod method = cl.getDeclaredMethod("getA2"); // here you have lot of options to explore method.insertBefore("System.out.println(Thread.currentThread().getStackTrace()[0].getClassName()+ Thread.currentThread().getStackTrace()[0].getMethodName());"); b = cl.toBytecode(); } catch (Exception e) { System.err.println("Could not instrument " + name + ", exception : " + e.getMessage()); } finally { if (cl != null) { cl.detach(); } } return b; }
步骤3-为代理类创建jar文件(你必须设置带有premain类的清单文件,并添加javaassit jar)给出构建文件的片段 - 你也可以手动完成
<jar destfile="build/jar/BasicAgent.jar" basedir="build/classes"> <manifest> <attribute name="Manifest-Version" value="1.0"/> <attribute name="Premain-Class" value="com.sk.agent.basic.BasicAgent"/> <attribute name="Boot-Class-Path" value="../lib/javassist.jar"/> </manifest> </jar>
步骤4-使用java代理运行主应用程序 - 在此之前将VM参数设置为加载代理
-`javaagent:D:\softwares\AgentProject\AgentLib\build\jar\BasicAgent.jar`
先决条件:您需要javassist.jar
在课程路径中.