Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Перехват вызовов методов без проксирования


Автор: Stampede 29.9.2006, 23:45
Вот уже некоторое время ломаю голову, как можно было бы перехватывать вызовы в самом классе, без оборачивания его в динамический прокси. Чтобы было понятнее, о чем речь, приведу пример более или менее правдоподобной ситуации.

Допустим, у нас есть иерархи классов: абстрактный Pet и его конкретные реализации:

Код

ipublic abstract class Pet {
    public abstract String getType() {
    }

    public abstract String speak() {
    }
}

public class Dog extends Pet {
    public String getType() {
        return "dog";
    }

    public String speak() {
        return "Arf!";
    }
}

public class Cat extends Pet {
    public String getType() {
        return "cat";
    }

    public String speak() {
        return "Meou!";
    }
}


Допустим, я разрабатываю API общего пользования для онлайновых зоомагазинов, и я не знаю наперед, какие конкретные реализации будут у класса Pet. Мне для моих нужд достаточно просто знать, как зверек называется и какие звуки он издает. Очень хорошо.

Теперь представим, что некто решил сделать свой тип многоязычным, и при инициализации лезет в какой-нибудь файл или базу данных, чтобы извлечь оттуда таблицу звуков. На такой случай я определяю контракт: дай своему загрузочному методу название, начинающееся на "load", и я предоставлю тебе дополнительный сервис. Например, буду засекать время начала и конца операции загрузки, и выводить это дело в лог.

Так, чтобы он мог написать:

Код

ipublic class Frog extends Pet {
    private Map<Locale, String> soundMap;
    //....
    public String speak() {
        if (soundMap == null) {
            loadSounds();
        }
        return soundMap.get(Locale.getDefault());
    }

    private void loadSounds() {
        // Тут собственно загружается таблица
    }
}


А теперь внимание, вопрос: как мне в классе Pet встроить перехватчик, чтобы он перехватывал все без исключения вызовы (включая методы, объявленные в дочерних классах), и в случае если метод начинается на load, оформлял бы его вызов примерно таким образом:

Код

if (method.getName().startsWith("load")) {
    long t = System.currentTimeMillis();
    Object result = method.invoke(obj, args);
    logger.debug("Method " + method.getName() + " executed in " + (System.currentTimeMillis() - t));
    return result;
}


Если воспользоваться механизмом динамических прокси, то это делается в два счета. Но тогда объекты у нас будут уже не оригинальные Pets, а нечто другое. А хотелось бы, чтобы были именно оригинальные объекты - по множеству разных причин. Например, чтобы их можно было создавать обычным конструктором.

Будут какие-нибудь предложения? Приветствуются любые идеи.

Автор: AntonSaburov 30.9.2006, 14:07
Я как-то изучал AspectJ - так вот он похоже не генерит прокси, а обрабатывает нужные классы и делает в них вставки. Правда делает это он на этапе компиляции. Зайди сюда - http://www.eclipse.org/aspectj/
Хотя может я что-то не так понял - просматривал просто

Автор: Stampede 30.9.2006, 14:25
Ага, буду смотреть. Меня в свое время смутило то, что у них был какой-то свой Java-подобный язык. Мож чего не понял smile

Автор: AntonSaburov 30.9.2006, 15:11
Цитата(Stampede @  30.9.2006,  14:25 Найти цитируемый пост)
что у них был какой-то свой Java-подобный язык.

Да, там есть такое. Он описывает те самые аспекты, которые потом буду вставляться в нужные места.
Но там мне помню понравилось, что никто не мешает собирать без изменений без включения аспектов.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)