starter joinpoint example baeldung spring aop spring-aop

joinpoint - spring-aop maven



Obtener proxy AOP desde el objeto en sí (3)

¿Es posible obtener el proxy de un objeto dado en Spring? Necesito llamar a una función de una subclase. Pero, obviamente, cuando hago una llamada directa, los aspectos no se aplican. Aquí hay un ejemplo:

public class Parent { public doSomething() { Parent proxyOfMe = Spring.getProxyOfMe(this); // (please) Method method = this.class.getMethod("sayHello"); method.invoke(proxyOfMe); } } public class Child extends Parent { @Secured("president") public void sayHello() { System.out.println("Hello Mr. President"); } }

He encontrado una manera de lograr esto. Funciona, pero creo que no es muy elegante:

public class Parent implements BeanNameAware { @Autowired private ApplicationContext applicationContext; private String beanName; // Getter public doSomething() { Parent proxyOfMe = applicationContext.getBean(beanName, Parent.class); Method method = this.class.getMethod("sayHello"); method.invoke(proxyOfMe); } }


Este truco es extremadamente incómodo, considere refactorizar su código o usar el tejido AspectJ. Usted puede sentirse advertido, aquí está la solución.

AopContext.currentProxy()

JavaDoc . Lo escribí here y here .


Puede utilizar un postprocesador de bean para establecer una referencia al proxy en el bean de destino. Mueve los específicos de Spring de tus beans a una sola clase.

Post-procesador

import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class SelfReferencingBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof SelfReferencingBean) { ((SelfReferencingBean) bean).setProxy(bean); } return bean; } }

Contexto

Registre el post-procesador en applicationContext.xml .

<bean id="srbpp" class="SelfReferencingBeanPostProcessor"/>

Frijoles

Cada bean debe implementar SelfReferencingBean para indicar al postprocesador que necesita una referencia al proxy.

public interface SelfReferencingBean { void setProxy(Object proxy) ; }

Ahora implemente setProxy en cada bean que necesita llamarse a sí mismo a través de su proxy.

public class MyBean implements SelfReferencingBean { MyBean proxy; @Override public void setProxy(Object proxy) { this.proxy = (MyBean) proxy; } }

Podría poner este último bit de código en una clase base de bean si no le importa convertir el proxy al tipo de bean cuando invoca métodos directamente en él. Ya que estás pasando por Method.invoke , ni siquiera necesitarías el elenco.

Con un poco de trabajo, apuesto a que esto podría convertirse en un procesador de anotaciones a la @Autowired . Ahora que lo pienso, no recuerdo si intenté agregar una auto-referencia usando @Autowired .

public class MyBean implements SelfReferencingBean { @Autowired MyBean proxy; }


AopContext.currentProxy() como lo sugiere Tomasz funcionará. Una solución más genérica, que funcionará fuera de la clase de proxy es convertir el objeto a org.springframework.aop.framework.Advised y obtener .getTargetSource().getTarget()

Lo primero (obtener el objeto real del objeto proxy) es algo que realmente no debería necesitar. Por otro lado, obtener el proxy de destino puede ser útil en alguna clase de utilidad que inspecciona los beans existentes para agregar alguna característica.