8

我们正在使用 SpringTransactionInterceptor来设置一些数据库分区信息,ThreadLocal只要执行标记有@Transactional注释的 DAO 方法。我们需要它能够将我们的查询路由到不同的数据库分区。

这适用于大多数 DAO 方法:

// this causes the invoke method to set a thread-local with the host name of
// the database server the partition is on
@Transactional
public int deleteAll() throws LocalDataException {

问题是当我们需要在 DAO 内部引用 DAO代理对象本身时。通常我们必须让调用者传入代理 dao:

public Pager<Foo, Long> getPager(FooDao proxyDao) {

这看起来像下面的代码,显然很恶心。

fooDao.getPager(fooDao);

问题是当我们在 FooDao 内部时,这this不是我们需要的代理 DAO。

是否有更好的机制让 bean 发现它周围有一个代理包装器?我查看了Spring AOPUtils,但我看不到找到对象代理的方法。例如我不想isAopProxy(...)。我也阅读了Spring AOP 文档,但除非我实现自己希望避免的 AOP 本机代码,否则我看不到解决方案。

ApplicationContextAware我怀疑我可能能够使用实用程序 bean 和方法将 DAO 注入到自身中setProxyDao(...),但这似乎也是一种 hack。任何其他想法如何检测代理以便我可以从 bean 本身中使用它?谢谢你的帮助。

4

3 回答 3

6

考虑到 AspectJ 编译时间或加载时间编织对您不起作用,按照您的建议提供了一个 hacky 解决方案:

按照以下思路创建接口:

public interface ProxyAware<T> {
    void setProxy(T proxy);
}

让您的 Dao 实现 ProxyAware 实现,现在创建一个带有 Ordered 接口的 BeanPostProcessor 以最后运行,如下所示:

public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (AopUtils.isAopProxy((bean))){
            try {
                Object target = ((Advised)bean).getTargetSource().getTarget();
                if (target instanceof ProxyAware){
                    ((ProxyAware) target).setProxy(bean);
                }
            } catch (Exception e) {
                // ignore
            }
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

这很丑陋,但有效。

于 2012-07-16T19:41:21.273 回答
4

Spring 提供了一个方便的静态实用程序AopContext.currentProxy()方法,该方法将代理返回到调用它的对象。

尽管使用它被认为是一种不好的做法,但从语义上讲,Java EE 中也存在相同的方法:SessionContext.getBusinessObject().

我写了几篇关于这种实用方法和各种陷阱文章1、2、3

于 2012-07-19T16:10:46.597 回答
3

使用 Spring 将 bean 引用注入 bean,甚至是同一个 bean,就像您对任何其他 bean 引用一样。无需特殊操作。

这种变量的存在在类设计中明确承认该类期望以某种方式被代理。这不一定是坏事,因为 aop 可以改变破坏类契约的行为。

bean 引用通常是针对一个接口的,对于自引用的内部方法,该接口甚至可以是不同的接口。

把事情简单化。那就是疯狂。:-)

更重要的是,确保语义有意义。这样做的需要可能是代码味道,该类混合了多个职责,最好分解为单独的 bean。

于 2012-08-14T04:22:04.603 回答