【问题标题】:References between Spring beans when using a NameSpaceHandler使用 NameSpaceHandler 时 Spring bean 之间的引用
【发布时间】:2011-02-27 10:17:10
【问题描述】:

我正在尝试使用 Spring 上下文命名空间在应用程序中构建一些现有的配置对象。我已经定义了一个上下文,如果工作令人满意的话,我几乎已经有了 - 但是,我希望我的命名空间定义的一个 bean 隐式引用另一个:

考虑名为“节点”的类:

public Class Node {
  private String aField;
  private Node nextNode;
  public Node(String aField, Node nextNode) {
  ...
}

现在在我的 Spring 上下文中,我有这样的东西:

<myns:container>
  <myns:node aField="nodeOne"/>
  <myns:node aField="nodeTwo"/>
</myns:container>

现在我希望 nodeOne.getNextNode() == nodeTwo 成为 true。这样nodeOne.getNextNode() 和nodeTwo 指的是同一个bean 实例。这些几乎就是我在AbstractBeanDefinitionParser 中的相关部分:

public AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
  ...
  BeanDefinitionBuilder containerFactory = BeanDefinitionBuilder.rootBeanDefinition(ContainerFactoryBean.class);
  List<BeanDefinition> containerNodes = Lists.newArrayList();
  String previousNodeBeanName;

  // iterate backwards over the 'node' elements
  for (int i = nodeElements.size() - 1; i >= 0; --i) {
    BeanDefinitionBuilder node = BeanDefinitionBuilder.rootBeanDefinition(Node.class);
    node.setScope(BeanDefinition.SCOPE_SINGLETON);

    String nodeField = nodeElements.getAttribute("aField");
    node.addConstructorArgValue(nodeField);

    if (previousNodeBeanName != null) {
      node.addConstructorArgValue(new RuntimeBeanReference(previousNodeBeanName));
    } else {
      node.addConstructorArgValue(null);
    }

    BeanDefinition nodeDefinition = node.getBeanDefinition();
    previousNodeBeanName = "inner-node-" + nodeField;
    parserContext.getRegistry().registerBeanDefinition(previousNodeBeanName, nodeDefinition);

    containerNodes.add(node);
  }
  containerFactory.addPropertyValue("nodes", containerNodes);
}

创建应用程序上下文时,我的 Node 实例被创建并被识别为单例。此外,nextNode 属性填充了具有先前节点配置的 Node 实例 - 但是,它不是相同的实例。

如果我在 Node 的构造函数中输出一条日志消息,我会看到为每个节点 bean 定义创建了两个实例。

我自己可以想到一些解决方法,但我热衷于使用现有模型。那么谁能告诉我如何传递这些运行时 bean 引用,以便为我的 Node 实例获得正确的单例行为?

【问题讨论】:

    标签: java spring namespaces


    【解决方案1】:

    我猜问题是你实际上有每个节点定义的两个实例——一个作为顶级节点(通过registerBeanDefinition),另一个在ContainerFactoryBean 的nodes 属性内。或许,你应该把RuntimeBeanReferences 放到ContainerFactoryBean 的节点中。

    【讨论】:

    • 我猜我正在创建一个命名实例和一个内部 bean 实例。即 - 两个 bean 定义,每个定义一个单例。
    【解决方案2】:

    我对这个问题有点困惑。当您说nodeOne.getNode() == nodeTwo 时,您是指nodeOne.getNextNode() 吗?像下面这样的东西不起作用吗?

    <bean id="nodeOne" class="org.foo.Node">
        <constructor-arg index="0" value="nodeOne" />
        <constructor-arg index="1" ref="nodeTwo" />
    </bean>
    <bean id="nodeTwo" class="org.foo.Node">
        <constructor-arg index="0" value="nodeTwo" />
        <constructor-arg index="1"><null/></constructor-arg>
    </bean>
    

    是不是因为您不想在 Spring 中指定 nextNode 而希望在代码中设置链接?

    下面的代码怎么样?这会查看所有 Node 类型的 bean 并在它们上调用 setNextNode()。这意味着您当然需要公开设置器。您可能还想让您的节点实现BeanNameAware,这样您就不必执行aField。

    public class NextBeanSetter implements InitializingBean, ApplicationContextAware {
        private ApplicationContext applicationContext;
        public void afterPropertiesSet() throws Exception {
            @SuppressWarnings("unchecked")
            Map<?, Node> beanMap = applicationContext.getBeansOfType(Node.class);
            Node previousNode = null;
            for (Node node : beanMap.values()) {
                node.setNextNode(previousNode);
                previousNode = node;
            }
        }
        public void setApplicationContext(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }
    }
    

    【讨论】:

    • 解决问题的有趣方法。但是,我觉得这应该可以在 BeanDefinitionParser 中实现。
    【解决方案3】:

    Bean 要么声明为单例,要么声明为非单例(=prototype)。也许您的创建是非单例的,因此请使用 bean 中的定义对其进行测试:

    <bean ... singleton="true" />;
    

    更多信息:http://static.springsource.org/spring/docs/1.2.9/reference/beans.html#beans-factory-modes

    【讨论】:

    • 我将它们设置为单例(参见上面的代码) - 另外,如果我调用 isSingleton - 它返回 true。
    猜你喜欢
    • 2016-05-17
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 2012-03-20
    • 2012-05-30
    • 1970-01-01
    • 2020-02-23
    • 2018-07-09
    相关资源
    最近更新 更多