如何拦截具有标准 Java 功能(无 AspectJ 等)的方法调用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/576918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:25:49  来源:igfitidea点击:

How do I intercept a method invocation with standard java features (no AspectJ etc)?

javareflectionmethods

提问by Tobias Hilka

I want to intercept all method invocations to some class MyClass to be able to react on some setter-invocations.

我想拦截对某个类 MyClass 的所有方法调用,以便能够对某些 setter 调用做出反应。

I tried to use dynamic proxies, but as far as I know, this only works for classes implementing some interface. But MyClass does not have such an interface.

我尝试使用动态代理,但据我所知,这只适用于实现某些接口的类。但是 MyClass 没有这样的接口。

Is there any other way, besides implementing a wrapper class, that delegates all invocations to a member, which is an instance of the MyClass or besided using AOP?

除了实现包装类之外,还有其他方法可以将所有调用委托给一个成员,该成员是 MyClass 的一个实例或除了使用 AOP 之外?

采纳答案by eljenso

As you note, you cannot use JDK dynamic proxies (no interface), but using Springand CGLIB (JAR included with Spring), you can do the following:

正如您所注意到的,您不能使用 JDK 动态代理(无接口),但使用Spring和 CGLIB(Spring 包含的 JAR),您可以执行以下操作:

public class Foo
{
    public void setBar()
    {
        throw new UnsupportedOperationException("should not go here");
    }

    public void redirected()
    {
        System.out.println("Yiha");
    }
}

Foo foo = new Foo();
ProxyFactory pf = new ProxyFactory(foo);

pf.addAdvice(new MethodInterceptor()
{
    public Object invoke(MethodInvocation mi) throws Throwable
    {
        if (mi.getMethod().getName().startsWith("set"))
        {
            Method redirect = mi.getThis().getClass().getMethod("redirected");
            redirect.invoke(mi.getThis());
        }
        return null;
    }
});

Foo proxy = (Foo) pf.getProxy();
proxy.setBar(); // prints "Yiha"

回答by Nick Fortescue

If you are prepared to do something really ugly, have a look at:

如果你准备做一些非常丑陋的事情,看看:

http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/

http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/

Basically the debugger interface ought to allow you to attach like a debugger, and hence intercept calls. Bear in mind I think this is a reallybad idea, but you asked if it was possible.

基本上调试器接口应该允许你像调试器一样附加,从而拦截调用。请记住,我认为这是一个非常糟糕的主意,但您问是否可能。

回答by Miserable Variable

There isn't a lot of magic in AspectJ. You can write your own agent. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.htmlseems to be good starting point.

AspectJ 中没有很多魔法。您可以编写自己的代理。http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html似乎是一个很好的起点。

回答by Gareth Davis

Java doesn't have any actual language features for method interception (not sure any static language does)

Java 没有任何用于方法拦截的实际语言功能(不确定任何静态语言都有)

I kinda like Nick's idea of using the debugger interface, that's just mean.

我有点喜欢 Nick 使用调试器界面的想法,这只是意思。

I think the short answer you need is: No there isn't a way of intercepting a method call in Java without actually replacing the class using a proxy or wrapper.

我认为您需要的简短回答是:没有办法在 Java 中拦截方法调用而不使用代理或包装器实际替换类。

Note: The AOP libraries just make this happen automatically.

注意:AOP 库只是让这自动发生。

回答by Aaron Digulla

Some of the Java gurus might frown upon this but I've had some good success with avoiding primitive types and setters altogether. My class looks like this:

一些 Java 大师可能对此不以为然,但我在完全避免原始类型和 setter 方面取得了一些不错的成功。我的课是这样的:

class Employee extends SmartPojo {
    public SmartString name;
    public SmartInt age;
}

You'll notice two things: 1. everything is public. 2. No constructor.

你会注意到两件事: 1. 一切都是公开的。2. 没有构造函数。

The magic happens in SmartPojo which searches for any field which implements the "Smart" interface and initializes it. Since this is no primitive (and no final class), I can add set() and get() methods for all fields anywhere in my model in a single place. So no setter/getter wastes anymore, it's stunningly simple to add notification (also in a single place), etc.

魔法发生在 SmartPojo 中,它搜索任何实现“智能”接口并初始化它的字段。由于这不是原始类(也没有最终类),我可以在一个地方为模型中任何位置的所有字段添加 set() 和 get() 方法。所以不再有 setter/getter 浪费,添加通知(也在一个地方)等非常简单。

True, this is no POJO anymore and it's not a Bean in most ways but I've found that these old ideas limit me more than they help. YMMV.

确实,这不再是 POJO,在大多数情况下它也不是 Bean,但我发现这些旧想法对我的限制比它们帮助的要多。天啊。

回答by Stas

  1. Why cannot your class implement an interface? You could just extract some interface from it containing all the methods that you want to intercept and use the dynamic proxies mechanism easily. It's also a good programming practice to code with interfaces and not classes.

  2. You could use Spring framework with Spring AOP capabilities (which are using dynamic proxies inside) to do it. You will just have to define your class as a Spring bean in the configuration file and clients of your class will have to either get its instance from the Spring application context or as a dependency automatically (by defining the setMyClass(MyClass mc) method for instance). From there you can easily go to defining an aspect that intercepts all the method calls to this class.

  1. 为什么你的类不能实现接口?您可以从中提取一些包含您想要拦截的所有方法的接口,并轻松使用动态代理机制。使用接口而不是类进行编码也是一种很好的编程习惯。

  2. 您可以使用具有 Spring AOP 功能(在内部使用动态代理)的 Spring 框架来做到这一点。您只需在配置文件中将类定义为 Spring bean,类的客户端必须从 Spring 应用程序上下文中获取其实例或自动作为依赖项(例如通过定义 setMyClass(MyClass mc) 方法) )。从那里你可以很容易地定义一个方面来拦截对这个类的所有方法调用。

回答by Pierantonio

I just developed a small framework for this purpose. You can check it out at: http://code.google.com/p/java-interceptor/(use svn to check out).

我刚刚为此开发了一个小框架。您可以在以下网址查看:http: //code.google.com/p/java-interceptor/(使用 svn 进行查看)。