example advice java spring spring-aop

java - advice - AOP de primavera no funciona para llamar al método dentro de otro método



spring boot aop example (6)

El aspecto se aplica a un proxy que rodea al bean. Tenga en cuenta que cada vez que obtiene una referencia a un bean, en realidad no es la clase a la que se hace referencia en su configuración, sino una clase sintética que implementa las interfaces pertinentes, delegando en la clase real y agregando funcionalidades, como su AOP.

En el ejemplo anterior, está invocando directamente a la clase, mientras que si esa instancia de clase se inyecta en otro como Spring Bean, se inyecta como su proxy y, por lo tanto, las llamadas a métodos se invocarán en el proxy (y los aspectos se activarán )

Si quiere lograr lo anterior, puede dividir method1 / method2 en beans separados, o usar un framework AOP no orientado a la primavera.

El documento de Spring detalla esto y un par de soluciones (incluida mi primera sugerencia anterior)

Hay dos métodos definidos en ABC.java

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

Quiero tener AOP en la llamada del método2 . Así que, creé una clase, AOPLogger.java , que tiene funcionalidad de aspecto provista en un método checkAccess
En el archivo de configuración, hice algo como a continuación

<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>

Pero cuando se llama a mi método2, la funcionalidad AOP no se invoca, es decir, no se invoca el método checkAccess de la clase AOPLogger.

¿Algo que me falta?


El marco de Spring AOP está basado en "proxy" y se explica muy bien aquí: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies

Cuando Spring construye un bean que está configurado con un aspecto (como "ABC" en su ejemplo), realmente crea un objeto "proxy" que actúa como el bean real. El proxy simplemente delega las llamadas al objeto "real" pero al crear esta indirección, el proxy tiene la oportunidad de implementar el "consejo". Por ejemplo, su consejo puede registrar un mensaje para cada llamada de método. En este esquema, si el método en el objeto real ("método1") llama a otros métodos en el mismo objeto (por ejemplo, método2), esas llamadas suceden sin proxy en la imagen, por lo que no hay ninguna posibilidad de implementar ningún consejo.

En su ejemplo, cuando se llama a method1 (), el proxy tendrá la oportunidad de hacer lo que se supone que debe hacer, pero si method1 () llama a method2 (), no hay ningún aspecto en la imagen. Sin embargo, si se llama a method2 desde algún otro bean, el proxy podrá realizar el consejo.

Espero que esto ayude.

Gracias, Raghu



Se puede hacer por autoinyección. Puede llamar al método interno a través de una instancia inyectada:

@Component public class Foo { @Resource private Foo foo; public void method1(){ .. foo.method2(); .. } public void method2(){ .. } }

Desde Spring 4.3 también puedes hacerlo usando @Autowired.

A partir de 4.3, @Autowired también considera las auto referencias para inyección, es decir, las referencias al bean que se inyecta actualmente.


Tuve el mismo tipo de problema y BeanNameAware implementando Spring ApplicationContextAware , BeanNameAware e implementando los métodos correspondientes como se muestra a continuación.

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; }

luego reemplacé this. con ((ABC) applicationContext.getBean(beanName)). al llamar a los métodos de la misma clase. Esto garantiza que las llamadas a métodos de la misma clase solo se realicen a través del proxy.

Entonces method1() cambia a

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

Espero que esto ayude.


Usando @Autowired funciona. En lugar de llamar al método interno como this.method() , puedes hacer:

@Autowired Foo foo;

y luego llamar:

foo.method2();