被叫方是否知道来电者?

时间:2013-11-24 15:55:34

标签: java reflection

我有一个Java实用程序包,可以由多个服务(用Java编写)用于执行某些实用程序任务。

假设Java实用程序包名称为U,其中一个Service为S. Now.S调用U的函数F.

我的问题是,是否有一种方法,包U的功能F能够确定哪个服务S调用了它? 可以有多个服务S1,S2,...,Sn呼叫F.我需要知道一个呼叫,哪个服务Sx正在呼叫该特定的F.

3 个答案:

答案 0 :(得分:4)

您可以使用类似下面的内容,只需要创建函数findServiceContainingClass将类名映射到服务(或null):

void callee() {
    StackTraceElement[] st = new RuntimeException().getStackTrace();
    for (int i = 1; i < st.length; i++) {
        Service service = findServiceContainingClass(st[i].getClassName());
        if (service != null) break;
    }
    // ... use service
}

然而,根据调用者的不同,使代码行为不同被认为是不好的做法。我会将此类代码仅作为最后的手段。 (在调试期间可以在断点条件下使用它。也许这就是你想要的。)

答案 1 :(得分:2)

Java中的面向对象编程声明您的服务是调用的范围,没有别的(忘记static)。因此除了将S实例作为参数传递之外,没有正常的方法可以找到调用实例方法的人。

但这并不意味着它是不可能的。

如果您只需要知道来电者的类型,可以使用Thread.currentThread().getStackTrace()

StackTraceElement[] elements = Thread.currentThread().getStackTrace()
StackTraceElement caller = elements[elements.length - 2];
printLn(caller.getClassName());

正如我在开头所说,它完全是反客观的Java代码。

如果您需要引用确切的实例,您可能应该将调用者添加为调用参数。我假设如果你想引用调用者,callee的代码是由你编写的,所以你可以这样做。 至于我这是最好的选择,因为如果你需要在被调用者范围内调用者,你应该直接传递它。 其他选项是在{{{{em>上设置调用者1}},但你不相信开发人员每次都会这样做。

如果无法更改界面,并且U是界面,则可以创建U构建器对象:

U

之后,您有另外的调用上下文(public class UBuilder { public U getS(final S caller) { Proxy.newProxyInstance(getClass().getClassLoader(), U.class, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // store caller value on some ThreadLocal variable try { method.invoke(proxy, args); } finally { // remove caller from ThreadLocal variable } } } } } )引用ThreadLocal实例。

如果S不是界面UJavassist或类似内容会有所帮助,但前提是调用的方法不是静态的或最终的。

如果CgLib是静态的或最终的,我只会看到极其苛刻的答案。也许创建自己的模仿F的界面,U中的转发方法调用可能是某种方式。当然S应该引用这个接口,而不是直接InvocationHandler

希望它有所帮助。

答案 2 :(得分:0)

如果需要一些由该实用程序方法执行的特定于服务的代码,我将在实用程序类中声明一个接口,并让服务将其实例传递给该方法。

这是一个人为的例子:

public class Utility {

    public interface UtilityInterface {

        public void specificBehavior( Object arg );
    }

    public void utilityMethodF( UtilityInterface utilityInterface, Object... args ) {

        // perform work with args or whatever

        utilityInterface.specificBehavior( null );

        // perform work with args or whatever
    }

}