Obtenir un proxy AOP à partir de l'objet lui-même
Est possible pour obtenir le proxy d'un objet donné au Printemps? J'ai besoin d'appeler une fonction d'une sous-classe. Mais, évidemment, quand je fais un appel direct, les aspects ne sont pas appliquées. Voici un exemple:
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");
}
}
j'ai trouvé un moyen d'y parvenir. Cela fonctionne, mais je pense que ce n'est pas très élégant:
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);
}
}
3 réponses
ce hack est extrêmement embarrassant, s'il vous plaît envisager de reconfigurer votre code ou en utilisant AspectJ tissage. Vous pouvez vous sentir avertis, voici la solution
AopContext.currentProxy()
AopContext.currentProxy()
comme suggéré par Tomasz fonctionnera. Une solution plus générique, qui fonctionnera en dehors de la classe proxied est de lancer l'objet à org.springframework.aop.framework.Advised
et obtenir .getTargetSource().getTarget()
le PREMIER (obtenir l'objet réel à partir de l'objet proxy) est quelque chose dont vous ne devriez pas vraiment avoir besoin. D'autre part l'obtention de la cible procuration peut être utile dans certaines classe utilitaire qui inspecte les haricots existants afin d'ajouter certaines fonctionnalités.
vous pouvez utiliser un post-processeur de haricot pour définir une référence au proxy sur le haricot cible. Il déplace les caractéristiques de printemps de vos haricots à une seule classe.
Post-Processeur
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;
}
}
contexte
Enregistrer le post-processeur dans applicationContext.xml
.
<bean id="srbpp" class="SelfReferencingBeanPostProcessor"/>
haricots
chaque haricot doit implémenter SelfReferencingBean
pour dire au post-processeur qu'il a besoin d'une référence au proxy.
public interface SelfReferencingBean {
void setProxy(Object proxy) ;
}
implémente maintenant setProxy
dans chaque haricot qui doit s'appeler par son intermédiaire.
public class MyBean implements SelfReferencingBean {
MyBean proxy;
@Override
public void setProxy(Object proxy) {
this.proxy = (MyBean) proxy;
}
}
vous pouvez mettre ce dernier morceau de code dans une classe de base de haricot si vous ne vous gênez pas de lancer proxy
au type de haricot lors de l'appel de méthodes directement sur elle. Puisque vous traversez Method.invoke
vous ne le feriez pas même plus besoin de la fonte.
avec un peu de travail je parie que cela pourrait être converti en un processeur d'annotation a la @Autowired
. En y repensant, je ne me souviens même pas si j'ai essayé d'ajouter une référence personnelle en utilisant @Autowired
lui-même.
public class MyBean implements SelfReferencingBean {
@Autowired MyBean proxy;
}