从对象本身获取AOP代理

31

在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
请参见 使用Spring进行自我注入 - Vadzim
3个回答

26

这种方法非常笨拙,请考虑重构您的代码或使用AspectJ weaving。您已经被警告,以下是解决方案

AopContext.currentProxy()

JavaDoc。我在这里这里写了相关的博客。


1
谢谢,它起作用了!我在我的配置中添加了<aop:aspectj-autoproxy expose-proxy="true" />。无论如何,我正在阅读以尝试使用AspectJ。 - sinuhepop

16

AopContext.currentProxy()如Tomasz所建议的那样可以使用。更通用的解决方案,可以在代理类之外使用,是将对象转换为org.springframework.aop.framework.Advised类型,并调用.getTargetSource().getTarget()方法。

前者(从代理对象中获取真实对象)实际上并不是你真正需要的。另一方面,获取目标代理可能在某些实用程序类中很有用,这些类检查现有的bean以添加某些功能。


13

您可以使用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"/>

Java Bean

每个Java 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;
    }
}
如果您不介意在直接调用bean上的方法时将代理转换为bean类型,则可以将此代码段放入bean基类中。 因为您正在通过Method.invoke进行操作,所以您甚至不需要这样做。如果稍加修改,我敢打赌这可以转换为类似@Autowired的注释处理器。想想看,我甚至不记得是否尝试过使用@Autowired本身来添加自引用。
public class MyBean implements SelfReferencingBean {
    @Autowired MyBean proxy;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接