Как перехватить вызов метода стандартными функциями Java (без AspectJ и т. Д.)? - PullRequest
19 голосов
/ 23 февраля 2009

Я хочу перехватить все вызовы методов для некоторого класса MyClass, чтобы иметь возможность реагировать на некоторые вызовы сеттера.

Я пытался использовать динамические прокси, но, насколько я знаю, это работает только для классов, реализующих некоторый интерфейс. Но MyClass не имеет такого интерфейса.

Есть ли другой способ, кроме реализации класса-оболочки, который делегирует все вызовы члену, который является экземпляром MyClass или помимо использования AOP?

Ответы [ 7 ]

26 голосов
/ 23 февраля 2009

Как вы заметили, вы не можете использовать динамические прокси JDK (без интерфейса), но, используя Spring и CGLIB (JAR включен в Spring), вы можете сделать следующее:

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"
13 голосов
/ 23 февраля 2009

Если вы готовы сделать что-то действительно безобразное, взгляните на:

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

По сути, интерфейс отладчика должен позволять вам подключаться как отладчик и, следовательно, перехватывать вызовы. Имейте в виду, я думаю, что это действительно плохая идея, но вы спросили, возможно ли это.

2 голосов
/ 21 августа 2012

Я только что разработал небольшой фреймворк для этой цели. Вы можете проверить это по адресу: http://code.google.com/p/java-interceptor/ (используйте svn для проверки).

2 голосов
/ 23 февраля 2009

Java не имеет каких-либо реальных языковых функций для перехвата методов (не уверен, что у какого-либо статического языка есть)

Мне нравится идея Ника использовать интерфейс отладчика, это просто значит.

Думаю, вам нужен краткий ответ: нет, в Java нет способа перехватить вызов метода без фактической замены класса с помощью прокси или оболочки.

Примечание: библиотеки AOP просто делают это автоматически.

1 голос
/ 23 февраля 2009

Некоторые из Java-гуру могут не одобрить это, но у меня был некоторый хороший успех, когда я вообще избежал примитивных типов и сеттеров. Мой класс выглядит так:

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

Вы заметите две вещи: 1. все публично. 2. Нет конструктора.

Волшебство происходит в SmartPojo, который ищет любое поле, которое реализует «умный» интерфейс, и инициализирует его. Поскольку это не примитив (и не конечный класс), я могу добавить методы set () и get () для всех полей в моей модели в одном месте . Так что больше нет необходимости тратить сеттер / геттер, просто невероятно просто добавить уведомление (также в одном месте) и т. Д.

Да, это больше не POJO, и это не Бин в большинстве случаев, но я обнаружил, что эти старые идеи ограничивают меня больше, чем помогают. YMMV.

0 голосов
/ 23 февраля 2009
  1. Почему ваш класс не может реализовать интерфейс? Вы можете просто извлечь из него некоторый интерфейс, содержащий все методы, которые вы хотите перехватить, и легко использовать механизм динамических прокси. Это также хорошая практика программирования для кодирования с интерфейсами, а не с классами.

  2. Вы можете использовать Spring Framework с возможностями Spring AOP (которые используют динамические прокси внутри), чтобы сделать это. Вам просто нужно будет определить ваш класс как bean-компонент Spring в файле конфигурации, и клиенты вашего класса должны будут либо получить его экземпляр из контекста приложения Spring, либо автоматически как зависимость (определив, например, метод setMyClass (MyClass mc)). ). Оттуда вы можете легко перейти к определению аспекта, который перехватывает все вызовы методов этого класса.

0 голосов
/ 23 февраля 2009

В Аспекте не так много магии. Вы можете написать свой собственный агент. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html кажется хорошей отправной точкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...