Получить прокси AOP от самого объекта - PullRequest
21 голосов
/ 20 сентября 2011

Возможно ли получить прокси данного объекта в 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 ]

15 голосов
/ 20 сентября 2011

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

AopContext.currentProxy()

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

13 голосов
/ 20 сентября 2011

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

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

8 голосов
/ 01 июля 2012

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

Post-Processor

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

Context

Зарегистрировать постпроцессор в 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;
}
...