如何在Java中动态更改对象行为,动态代理是没用的

时间:2017-03-24 16:02:32

标签: java bytecode

以下是解释问题的代码段:

public class Demo {
    // I want to enhance this method.
    public String a() {
        return "A";
    }

    // this method is not enhanced but the internal a() invocation should be
    public String b() {
        return "-> " + a();
    }
}

我希望增强方法a(),并且在调用方法b()时,应执行增强的a()。我猜CGLIB代理不费力。

此外,此增强操作应该是对象级别而不是类级别。

public static void verify() {
    assert Objects.equals("-> A", new Demo().b());
    assert !Objects.equals("-> A", enhance(new Demo()).b());
}

public static Demo enhance(Demo demo) {
    throw new UnsupportedOperationException("I don't know how to do");
}

是否有解决此问题的解决方案?

顺便说一句:抱歉我的英语不好,但我认为我的意图很明确。

补编

实际上,我的问题是:

将记录异常堆栈跟踪,但其中一些使用detailMessagenew XXException("sensitive")字段中包含敏感数据,或者某些IOException将打印详细的绝对路径。< / p>

printStackTrace()将调用toString()方法,toString()方法将调用getMessage()方法。 (您可以看到JDK源代码)

我想提供一个实用程序方法来包装/增强Exception,让printStackTrace()不打印敏感数据,但打印堆栈跟踪以查找错误。 然后可以安全地将这些Exception对象发送到log4j。

4 个答案:

答案 0 :(得分:2)

我没有看到只是子类化的问题。

await

您仍然可以使用它来代替正常的演示:

class EnhancedDemo extends Demo{
    @Override
    public String a(){
        return "Enhanced A";
    }
}

这还不够吗?难道你不能重构你认为需要的代码来代替dependency injection吗?

答案 1 :(得分:0)

正如您所提到的,CGLIB代理(和Java动态代理)都有相同的问题。当从代理方法调用另一个方法时(在你的情况下,当b()调用a())时,使用引用'self',代理永远不会进入图片。

作为一种解决方法,您可以考虑将代理对象本身传递给类,如此SO Answer。线程问你一个类似的问题,'增强'是Spring的事务处理代理。 之后,您可以使用对所有地方的引用而不是直接调用。

您也可以考虑重构您的代码,以免出现这种情况。但根据您的使用案例,可能会或可能不会这样。

关于enhancement action should be object-level rather than class-level java动态代理在对象级别上工作的后一个问题。因此,如果您创建了该类的新对象而不对其进行代理,那么它将保持“无增强”。

答案 2 :(得分:0)

您似乎错误地接近了这个问题。 问题似乎不是&#34;如何动态更改垃圾&#34; &#34;如何正确设计我的代码以允许动态更改方法的实现&#34;。答案是:为方法实现策略模式功能。

以下是一个例子:

public interface MethodAStrategy
{
    String methodAImplementation();
}

public class SimpleAStrategy
implements MethodAStrategy
{
    public String methodAImplementation()
    {
        return "a";
    }
}

public class EnhancedAStrategy
implements MethodAStrategy
{
    public String methodAImplementation()
    {
        return "enhanced a";
    }
}

public class EnhancedDemo
extends Demo
{
    private MethodAStrategy strategyForMethodA;
    private MethodAStrategy strategyForMethodB;

    public EnhancedDemo()
    {
        strategyForMethodA = new SimpleAStrategy();
        strategyForMethodB = new EnhancedAStrategy()
    }

    public String a()
    {
        return strategyForMethodA.methodAImplementation();
    }

    public String b()
    {
        return "->" + strategyForMethodB.methodAImplementation();
    }

    // as desired, add methods to change the strategies.
}

答案 3 :(得分:0)

由于您的真正问题是阻止将某些数据记录到文件中,最简单的方法是在日志记录点拦截此数据。扩展Log4J FileAppender并重新编写绝对路径应该很容易。然后,您只需要确保使用自定义appender而不是常规appender,但这比您的想法更容易。