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

3 ответа

Решение

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

AopContext.currentProxy()

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

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

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

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

Пост-процессор

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

Фасоль

Каждый бин должен реализовывать SelfReferencingBean сообщить постпроцессору, что ему нужна ссылка на прокси.

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

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

public class MyBean implements SelfReferencingBean {
    MyBean proxy;

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

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

Немного потрудившись поспорить, что это можно преобразовать в процессор аннотаций а-ля @Autowired, Если подумать, я не помню, пытался ли я добавить ссылку на себя, используя @Autowired сам.

public class MyBean implements SelfReferencingBean {
    @Autowired MyBean proxy;
}
Другие вопросы по тегам