Получить прокси-сервер 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);
    }
}

Ответ 1

Этот взлом крайне неудобен, пожалуйста, подумайте о том, как реорганизовать ваш код или использовать плетение AspectJ. Вы можете чувствовать себя предупрежденным, вот решение

AopContext.currentProxy()

JavaDoc. Я писал об этом здесь и здесь.

Ответ 2

AopContext.currentProxy(), как предложил Томаш. Более общее решение, которое будет работать вне класса прокси, - это передать объект в org.springframework.aop.framework.Advised и получить .getTargetSource().getTarget()

Первое (получение реального объекта из прокси-объекта) - это то, что вам действительно не нужно. С другой стороны, получение целевого прокси-сервера может быть полезным в некоторых классах, которые проверяют существующие beans, чтобы добавить некоторые функции.

Ответ 3

Вы можете использовать постпроцессор bean, чтобы установить ссылку на прокси-сервер в целевом bean. Он перемещает Spring -специфики из вашего beans в один класс.

постпроцессор

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

Теперь реализуем setProxy в каждом bean, который должен вызывать себя через свой прокси.

public class MyBean implements SelfReferencingBean {
    MyBean proxy;

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

Вы можете поместить этот последний бит кода в базовый класс bean, если вы не возражаете против ввода proxy в bean типа при вызове методов непосредственно на нем. Поскольку вы проходите через Method.invoke, вам даже не понадобится бросок.

С небольшой работой, я уверен, это можно было бы преобразовать в обработчик аннотации a la @Autowired. Подумайте об этом, я не помню, даже если я попытался добавить самооценку, используя @Autowired.

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