Пружина 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. Это также требует некоторой дополнительной конфигурации, когда прокси-сервер находится создан.