Аспект Spring не применяется для созданного компонента ServiceFactoryBean - PullRequest
1 голос
/ 06 декабря 2011

У меня проблема с применением аспекта к компоненту, созданному ServiceFactoryBean (загружен ServiceLoader).

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

...
<aop:aspectj-autoproxy/>

<bean id="myBean"
      class="org.springframework.beans.factory.serviceloader.ServiceFactoryBean"
      p:serviceType="com.test.MyInterface"/>

<bean id="myAnotherBean"
      class="com.test.MyAnotherBean"/>

Мой аспект определяется следующим образом:

@Aspect
public class MyAspect {

    @Pointcut("bean(myBean)")
    public void foo() {
    }

    @Pointcut("bean(myAnotherBean)")
    public void bar() {
    }

    @Around("foo()")
    public Object doFoo(final ProceedingJoinPoint jp) throws Throwable {
        return timed(jp, "foo");
    }

    @Around("bar()")
    public Object doBar(final ProceedingJoinPoint jp) throws Throwable {
        return timed(jp, "bar");
    }

    private ThreadLocal<StopWatch> stopWatch = new ThreadLocal<StopWatch>();

    private Object timed(final ProceedingJoinPoint jp, final String taskName) throws Throwable {
        stopWatch.get().add(taskName);
        try {
            return jp.proceed();
        } finally {
            if (stopWatch.get() != null) {
                stopWatch.get().stop(taskName);
            }
        }
    }
}

По неизвестной причине этот аспект применяется только к вызовам myAnotherBean, но не к вызову myBean. Есть идеи?

1 Ответ

0 голосов
/ 06 декабря 2011

Как подсказывает smp7d в комментариях к вашему вопросу, прокси, созданные Spring, могут иметь к ним только совет, если вызов метода поступает из другого объекта. Самостоятельного вызова недостаточно, чтобы вызвать совет.

http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch08s06.html

public class Main {

   public static void main(String[] args) {

      ProxyFactory factory = new ProxyFactory(new SimplePojo());
      factory.addInterface(Pojo.class);
      factory.addAdvice(new RetryAdvice());

      Pojo pojo = (Pojo) factory.getProxy();

      // this is a method call on the proxy!
      pojo.foo();
   }
}

Ключевым моментом, который необходимо понять, является то, что клиентский код внутри main (..) класса Main имеет ссылку на прокси. Это означает, что вызовы методов для этой ссылки на объект будут вызовами прокси-сервера, и, таким образом, прокси-сервер сможет делегировать всем перехватчикам (рекомендации), которые имеют отношение к этому конкретному вызову метода. Однако, как только вызов, наконец, достигнет целевого объекта, в этом случае ссылка SimplePojo, любые вызовы методов, которые он может сделать сам, такие как this.bar () или this.foo (), будут вызываться против это ссылка, а не прокси. Это имеет важные последствия. Это означает, что самовывоз не приведет к тому, что совет, связанный с вызовом метода, получит шанс на выполнение.

...