Пружина AOP не работает для вызова метода внутри другого метода

есть два метода, определенные в ABC.java

public void method1(){
   .........
   method2();
  ...........
}


public void method2(){
  ...............
  ...............  
}

Я хочу иметь AOP по вызову method2.Так что ... , Я создал один классAOPLogger.java, имея функциональность аспекта, предусмотренную в методе checkAccess
В файле конфигурации, я сделал что-то вроде ниже

<bean id="advice" class="p.AOPLogger" />
<aop:config>
  <aop:pointcut id="abc" expression="execution(*p.ABC.method2(..))" />
  <aop:aspect id="service" ref="advice">
    <aop:before pointcut-ref="abc" method="checkAccess" />          
  </aop:aspect>
</aop:config>

но когда вызывается мой method2, функциональность AOP не вызывается, т. е. checkAccess метод не получает вызывается класса AOPLogger.

что-нибудь мне не хватает?

7 ответов


аспект применяется к прокси вокруг зерен. Обратите внимание, что каждый раз, когда вы получаете ссылку на bean, это на самом деле не класс, указанный в вашей конфигурации, а синтетический класс, реализующий соответствующие интерфейсы, делегирующий фактическому классу и добавляющий функциональность, такую как ваш AOP.

в приведенном выше примере вы вызываете напрямую в классе, тогда как если этот экземпляр класса вводится в другой как Spring bean, это вводится как его прокси-сервер, и, следовательно, вызовы методов будут вызываться на прокси-сервере (и аспекты будут инициированы)

Если вы хотите достичь вышеуказанного, вы можете разделить method1/method2 в отдельные бобы или используйте структуру AOP, не ориентированную на пружину.

на Spring doc подробнее об этом и несколько обходных путей (включая мое первое предложение выше)


оно может быть сделан использованием впрыски собственной личности. Вы можете вызвать внутренний метод через injected instance:

@Component
public class Foo {
    @Resource
    private Foo foo;

    public void method1(){
        ..
        foo.method2();
        ..
    }
    public void method2(){
        ..
    }
}

С весны 4.3 вы также можете сделать это с помощью @Autowired.

по состоянию на 4.3, @Autowired также рассматривает ссылки на себя для инъекции, т. е. ссылки на боб, который в настоящее время вводится.


у меня была такая же проблема и я преодолел путем внедрения весны ApplicationContextAware,BeanNameAware и внедрении соответствующих методов, как показано ниже.

class ABC implements ApplicationContextAware,BeanNameAware{

      @Override
      public void setApplicationContext(ApplicationContext ac) throws BeansException {
          applicationContext=ac;
      }

      @Override
      public void setBeanName(String beanName) {
          this.beanName=beanName;
      }
      private ApplicationContext applicationContext;
      private String beanName;
}

затем Я заменил this. С ((ABC) applicationContext.getBean(beanName)). при вызове методов этого же класса. Это гарантирует, что вызовы методов того же класса происходят только через прокси-сервер.

так method1() изменения

 public void method1(){
    .........
    ((ABC) applicationContext.getBean(beanName)).method2();
    ...........
  }

надеюсь, что это помогает.


Spring AOP framework основан на "прокси", и это очень хорошо объясняется здесь: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies

когда Spring создает bean, который настроен с аспектом (например, "ABC" в вашем примере), он фактически создает объект "proxy", который действует как реальный bean. Прокси-сервер просто делегирует вызовы" реальному " объекту, но, создавая эту косвенность, прокси получает шанс реализовать "совет". Например, ваш совет может регистрировать сообщение для каждого вызова метода. В этой схеме, если метод в реальном объекте ("method1") вызывает другие методы в том же объекте (скажем, method2), эти вызовы происходят без прокси-сервера на картинке, поэтому у него нет шансов реализовать какие-либо советы.

в вашем примере, когда вызывается method1 (), прокси получит возможность делать то, что он должен делать, но если method1 () вызывает method2 (), есть никакого аспекта в картине. Как бы то ни было, если method2 вызывается из какого-либо другого компонента, прокси сможет выполнить совет.

надеюсь, что это помогает.

спасибо, Рагху!--3-->


используя @Autowired это работает. Вместо вызова внутреннего метода как this.method(), вы можете сделать:

@Autowired
Foo foo;

а потом звонит:

foo.method2();

невозможно то, чего вы хотите достичь. Объяснение находится в Весенняя Справочная Документация.


Как указано в весной документы, глава 5.6.1 понимание прокси AOP, есть еще один способ, которым вы можете сделать:

public class SimplePojo implements Pojo {

    public void foo() {
        // this works, but... gah!
        ((Pojo) AopContext.currentProxy()).bar();
    }

    public void bar() {
        // some logic...
    }
}

хотя автор не рекомендует этот способ. Потому что:

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