web-dev-qa-db-ja.com

オブジェクト自体からAOPプロキシを取得する

Springで特定のオブジェクトのプロキシを取得することは可能ですか?サブクラスの関数を呼び出す必要があります。しかし、明らかに、私が直接電話をかけるとき、側面は適用されません。次に例を示します。

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

私はこれを達成する方法を見つけました。それは機能しますが、あまりエレガントではないと思います。

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);
    }
}
24
sinuhepop

このハックは非常に厄介です。コードをリファクタリングするか、AspectJウィービングを使用することを検討してください。あなたは警告を感じるかもしれません、ここに解決策があります

AopContext.currentProxy()

JavaDoc 。私はそれについてブログを書きました ここ そして ここ

18

Tomaszが提案したAopContext.currentProxy()は機能します。プロキシされたクラスの外部で機能するより一般的な解決策は、オブジェクトを_org.springframework.aop.framework.Advised_にキャストし、.getTargetSource().getTarget()を取得することです。

前者(プロキシされたオブジェクトから実際のオブジェクトを取得する)は、実際には必要ないものです。一方、ターゲットプロキシを取得することは、機能を追加するために既存のBeanを検査するユーティリティクラスで役立つ場合があります。

14
Bozho

Beanポストプロセッサを使用して、ターゲットBeanのプロキシへの参照を設定できます。 Spring固有のものをBeanから単一のクラスに移動します。

後処理

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

コンテキスト

ポストプロセッサをapplicationContext.xmlに登録します。

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

Beans

各BeanはSelfReferencingBeanを実装して、プロキシへの参照が必要であることをポストプロセッサに通知する必要があります。

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

次に、プロキシを介して自分自身を呼び出す必要がある各BeanにsetProxyを実装します。

public class MyBean implements SelfReferencingBean {
    MyBean proxy;

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

メソッドを直接呼び出すときにproxyをBeanの型にキャストしてもかまわない場合は、この最後のコードをBean基本クラスに入れることができます。 Method.invokeを通過しているので、キャストすら必要ありません。

少しの作業で、これを@Autowiredの注釈プロセッサに変換できると思います。考えてみると、@Autowired自体を使用して自己参照を追加しようとしたかどうかは思い出せません。

public class MyBean implements SelfReferencingBean {
    @Autowired MyBean proxy;
}
8
David Harkness