2016-03-19 9 views
0

Мы ищем решение для отслеживания состояния клиентского экземпляра POJO с помощью программы. Мы ожидаем, что каждый раз, когда происходит изменение POJO, это состояние создается с помощью сеттеров. Мы создали OGNL-based watch/event-bus, и когда будет произведено изменение, мы отправим надлежащее OgnlChangeEvent на нашу шину событий.Как отслеживать состояние POJO с использованием генерации кода

До сих пор мы рассматривали решение AiffJ/cglib/object Diff, но все они занимали слишком много процессорного времени. Наше текущее решение основано на Spring MethodInterceptor, и мы создаем новый экземпляр Proxy каждый раз, когда вызывается метод Getter.

На этом этапе мы начинаем рассматривать решения для генерации кода, и мы наткнулись на Byte Buddy. Правильно ли это направление? Можем ли мы создать новый Class, который расширит наше клиентское состояние POJO и сообщит о его префиксе OGNL до тех пор, пока не будет вызван метод setter?

+0

Можете ли вы подробно рассмотреть проблему производительности с некоторыми измерениями? Сколько раз вы вызываете метод, каково время выполнения метода без отслеживания изменений, каково время выполнения с отслеживанием изменений и общий обзор того, что вы делаете в части отслеживания изменений вашего кода? –

+0

Я согласен с @ NándorElődFekete. Трудно поверить, что AspectJ должен быть медленнее, чем Spring AOP. Если это так, вы должны делать что-то неправильно, потому что AspectJ очень эффективен. Может быть, мы сможем помочь, если увидим ваши аспекты. Но если вы довольны ByteBuddy, возможно, этот комментарий устарел. В последнее время я не читал много, потому что я был занят, поэтому я немного опоздал, чтобы прокомментировать здесь, может быть. – kriegaex

ответ

2

Byte Buddy - это инструмент генерации кода, и, конечно же, можно реализовать такое решение. Для создания класса, который перехватывает сеттер, вы бы написать код:

new ByteBuddy() 
    .subclass(UserPojo.class) 
    .method(ElementMatchers.isSetter()) 
    .intercept(MethodDelegation.to(MyInterceptor.class) 
      .andThen(SuperMethodCall.INSTANCE) 
    .make(); 

Где бы вы написать перехватчик так:

public class MyInterceptor { 
    public static void intercept(Object value) { 
    // business logic comes here 
    } 
} 

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

Я, однако, смущен, что вы подразумеваете под исполнитель. Приведенный выше код оказывается для меня так же, как создание класса, как:

class UserClass { 
    String value; 
    void setValue(String value) { 
    this.value = value; 
    } 
} 

class InstrumentedUserClass extends UserClass { 
    @Override 
    void setValue(String value) { 
    MyInterceptor.intercept(value); 
    super.setValue(value); 
    } 
} 

производительность в основном зависит от производительности, что вы делаете в методе intercept.

И, наконец, я не понимаю, как cglib не работает для вас, но использование Spring - который строится поверх cglib - работает. Я подозреваю, что есть какая-то проблема с вашей логикой перехвата, которую вы должны изучить.

+0

спасибо :-) CGLIB работает для меня, а также для решения весенней оболочки. основной проблемой была и до сих пор производительность :-( –

1

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

Я не знаю много о вашем случае использования, но в целом я хотел бы спросить себя:

  • Какую информацию мне действительно нужно?
  • Каковы основные данные для получения этой информации?

Вы должны отделить базовый сбор данных от интерпретации этих данных (информации). Обычно интерпретация занимает больше времени. Основные данные - это данные, которые не могут быть получены из других данных. Например, день рождения - это базовые данные, а возраст - от дня рождения.

В методе перехватчика я бы

  • только собрать основные данные, такие как имя класса, имя метода и, возможно параметров.
  • отправьте эту информацию на какую-либо рабочую очередь
  • Позвольте фоновому работнику сгенерировать информацию, записать или перенести ее.

Фоновый работник может, например, интерпретируйте имя метода, чтобы узнать, является ли он аксессуаром или нет. Обычно вы делаете это, используя BeanInfo, который вы получаете от Introspector или, по крайней мере, отражения api.

+0

Спасибо René! самая потребляющая часть создавала новый прокси для каждого метода getter, чтобы продолжить получение префикса Ognl. Вот почему я искал решение для байтового инструментария. –