代码之家  ›  专栏  ›  技术社区  ›  teabot

使用命名空间处理程序时SpringBean之间的引用

  •  2
  • teabot  · 技术社区  · 16 年前

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

    考虑名为“node”的类:

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

    现在在我的春季环境中,我有这样的东西:

    <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 属性填充有 结点 具有先前节点配置的实例-但是,它 不是 相同的实例。

    如果我在中输出日志消息 结点 我看到为每个节点bean定义创建了两个实例。

    我可以自己想出一些解决办法,但我很想使用现有的模型。所以,有人能告诉我如何传递这些运行时bean引用,以便为我的 结点 实例?

    3 回复  |  直到 9 年前
        1
  •  1
  •   axtavt    16 年前

    我想问题在于,每个节点定义实际上有两个实例-一个作为顶级节点(通过 registerBeanDefinition 还有一个在里面 nodes 性质 ContainerFactoryBean . 或许,你应该 RuntimeBeanReference 节点到节点 集装箱工厂豆 .

        2
  •  1
  •   Gray droiddeveloper    16 年前

    我对这个问题有点困惑。当你说 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>
    

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

    下面的代码怎么样?这看了所有的豆子 Node 类型与调用 setNextNode() 在他们身上。这意味着您当然需要公开setter。您还可能希望实现节点 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;
        }
    }
    
        3
  •  0
  •   Sampada    9 年前

    bean要么声明为singleton,要么声明为非singleton(=原型)。也许您的是非单例创建的,所以用bean中的定义来测试它:

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

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