Иерархия класса Sonic ESB, вызывающая нежелательные множественные вызовы аспекта

Привет. Я пытаюсь использовать AspectJ с Sonic ESB для перехвата вызовов метода service() любой пользовательской службы ESB. Это означает, что я заранее не знаю тип класса обслуживания; Я знаю только, что он реализует интерфейс XQServiceEx. Реализованный метод service() вызывается контейнером Sonic каждый раз, когда сообщение JMS поступает в конечную точку службы. Однако контейнер имеет несколько сложную внутреннюю структуру, и я получаю три вызова моего совета для каждого входящего сообщения. (Надеюсь, моя терминология не за горами.)

Мой аспект выглядит так:

package com.ncr.eai.esb.aop;

import com.sonicsw.xq.XQService;
import com.sonicsw.xq.XQServiceEx;
import com.sonicsw.xq.XQServiceContext;
import com.sonicsw.xq.XQServiceException;
import com.ncr.eai.esb.*;

aspect XQServiceAspect {
 final String id = "O : ";

 pointcut serviceCall(XQServiceEx svc, XQServiceContext ctx) :
     call(void XQService.service(XQServiceContext)) &&
     target(svc) &&
     target(com.sonicsw.xq.XQService) &&
//     within(com.ncr..*) &&
     args(ctx);

    before(com.sonicsw.xq.XQServiceEx svc, XQServiceContext ctx): serviceCall(svc, ctx) {
     System.out.println(id + "Entering XQServiceEx.service(): " + thisJoinPointStaticPart.getSignature() + " " + svc + " " + ctx + " " + this);
    }

    void around(com.sonicsw.xq.XQServiceEx svc, XQServiceContext ctx): serviceCall(svc, ctx) {
     System.out.println(id + "In the around() advice before call to XQServiceEx.service(): " + thisJoinPointStaticPart.getSignature() + " " + svc + " " + ctx + " " + this);
     proceed(svc, ctx);
     System.out.println(id + "In the around() advice after call to XQServiceEx.service(): " + thisJoinPointStaticPart.getSignature() + " " + svc + " " + ctx + " " + this);
     }


    after(com.sonicsw.xq.XQServiceEx svc, XQServiceContext ctx) returning: serviceCall(svc, ctx) {
     System.out.println(id + "Returned from XQServiceEx.service(): " + thisJoinPointStaticPart.getSignature() + " " + svc + " " + ctx + " " + this);
    }
}

Вывод выглядит следующим образом:

O : Entering XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain@c64bc2 com.sonicsw.xqimpl.service.XQServiceContextImpl@97e765 com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : In the around() advice before call to XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain@c64bc2 com.sonicsw.xqimpl.service.XQServiceContextImpl@97e765 com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : Entering XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper@195638a com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : In the around() advice before call to XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper@195638a com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : Entering XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.ncr.eai.esb.ServiceFromAspect@1510b03 com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : In the around() advice before call to XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.ncr.eai.esb.ServiceFromAspect@1510b03 com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
  >>>> Inside of the actual service() method!
  >>>> About to exit the actual service() method!
O : In the around() advice after call to XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.ncr.eai.esb.ServiceFromAspect@1510b03 com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : Returned from XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.ncr.eai.esb.ServiceFromAspect@1510b03 com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : In the around() advice after call to XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper@195638a com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : Returned from XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper@195638a com.sonicsw.xqimpl.service.XQServiceChain$XQServiceContextWrapper@19c705e com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : In the around() advice after call to XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain@c64bc2 com.sonicsw.xqimpl.service.XQServiceContextImpl@97e765 com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f
O : Returned from XQServiceEx.service(): void com.sonicsw.xq.XQService.service(XQServiceContext) com.sonicsw.xqimpl.service.XQServiceChain@c64bc2 com.sonicsw.xqimpl.service.XQServiceContextImpl@97e765 com.ncr.eai.esb.aop.XQServiceAspect@d8ce8f

Я знаю, что результаты моих экспериментов здесь трудно читать, но каждый вызов service() приводит к последовательности из трех вызовов из com.sonicsw.xqimpl.service.XQServiceChain, com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper и com.ncr.eai.esb.ServiceFromAspect. Я хочу видеть только один вызов на сообщение, то есть один вызов service(). И я не знаю заранее, как будет называться третий класс. Этот тест выполняется с пользовательской службой с именем com.ncr.eai.esb.ServiceFromAspect, но могут быть десятки других служб, реализующих XQServiceEx, и я не хочу жестко кодировать их; они должны быть обнаружены во время выполнения. Я попытался добавить закомментированную фразу within(com.ncr..*), но ее использование помешало работе pointcut. Я также пытался исключить пакеты com.sonicsw с такими вещами, как !within(com.sonicsw..*), но это также остановило работу всех pointcuts.

Что касается развертывания, у меня есть этот аспект, и я делаю переплетение во время загрузки, добавляя javaagent в командную строку контейнера. Общая стратегия работает, но я потратил больше времени, чем хотел бы признать, пытаясь построить точечный разрез, который работает так, как хотелось бы.

Как получить только один звонок на сообщение?

Любые "советы" приветствуются!

Спасибо, Ли Грей, архитектор SOA NCR.


person Lee at NCR    schedule 26.01.2011    source источник


Ответы (1)


Похоже, что там происходит шаблон декоратора. Все, что вам, вероятно, нужно, это использовать cflowbelow(), чтобы избежать декорированных вызовов.

 pointcut serviceCall(XQServiceEx svc, XQServiceContext ctx) :
     call(void XQService.service(XQServiceContext)) &&
     target(svc) &&
     target(com.sonicsw.xq.XQService) &&
     args(ctx) &&
     !cflowbelow(call(void XQService.service(XQServiceContext)));
person ramnivas    schedule 26.01.2011
comment
Мне сказали в списке рассылки aspectj-users, что cflow оказывает большее влияние на производительность, поскольку он будет обрабатывать все сайты, а затем выполнять проверку для подтверждения потока управления. Было высказано предположение, что withincode(* *.service(XQServiceContext)) будет немного более производительным, потому что только один сайт будет обрабатываться во время плетения. Ваш способ абсолютно работает, но я подумал, что должен сообщить вам и об этом. - person Lee at NCR; 28.01.2011