如何(何时)初始化需要访问运行时才知道的其他bean的Spring bean? [英] How (and when) to initialize a Spring bean which needs to access other beans only known in runtime?

查看:191
本文介绍了如何(何时)初始化需要访问运行时才知道的其他bean的Spring bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在Java 5上运行的Spring webapp.这 我的applicationContext.xml文件:

I have a Spring webapp running on Java 5. This is was my applicationContext.xml file:

<bean id="child1" class="foo.ChildOne" />
<bean id="child2" class="foo.ChildTwo" />
<bean id="main" class="foo.Main">
  <property name="childrenList">
    <list value-type="foo.IChildren">
      <ref bean="child1" />
      <ref bean="child2" />
    </list>
  </property>
</bean>

ChildOneChildTwo类均实现IChildren接口.在我的Main类中,我定义了一个childrenList,其中填充了child1child2 bean. 容易,对吧?

Both ChildOne and ChildTwo classes implement the IChildren interface. And in my Main class, I have defined a childrenList which gets populated with child1 and child2 beans. Easy, right?

但是将来,可能没有child1,取而代之的是,我们可能会有一个基于另一个未知类的child81.而且,仅通过配置,它仍然必须在不触及当前代码或XML文件的情况下工作.此child81将在其自己的applicationContext文件中(在JAR中)定义,并且我们将在数据库字段(child2,child81,etc)中列出Bean名称.

But in the future, there might be no child1, and instead, we will maybe have a child81 based on another unknown class. And it still has to work without touching the current code or XML files, only through configuration. This child81 would be defined on its own applicationContext file (in a JAR), and we will list the bean names in a database field (child2,child81,etc).

我猜这不是一个好的设计模式.这很可能是一个可怕的,可怕的,痛苦的,可以在运行时更好地运行的设计,在以后的几年中,这将困扰我.但是我没有定义它,并且我不能更改它,因此,就这个问题而言,请假设它是可以的.

I guess that's not a good design pattern; most likely it's a terrible, horrible, painful, you-better-run-while-you-can design, which will haunt me in the years to come. But I didn't define it, and I can't change it, so please lets assume it's OK for the purpose of this question.

我不得不在运行时以某种方式检索它们,而不是使用applicationContext.xml自己注入bean.我也不能使用自动装配,因为我不知道bean是什么类,我所知道的是它们的所有类都实现了IChildren.

Instead of injecting the beans myself using the applicationContext.xml, I have to retrieve them somehow, in runtime. I can't use autowiring either, because I don't know what class the beans are, all I know is all of their classes implement IChildren.

因此,我已将主bean类设为ApplicationContextAware,并添加了此方法:

So I have made my main bean class ApplicationContextAware and I have added this method:

public void loadChildren() {
  if (childrenList == null) {
    childrenList = new LinkedList<IChildren>();
    for (String name : theListOfBeanNames) {
      childrenList.add((IChildren) context.getBean(name));
    }
  }
}

它工作正常;每个bean在其自己的applicationContext中定义,然后按名称检索它们.但是...我什么时候打loadChildren()?到目前为止,我正在每种方法的第一行中进行此操作.由于存在空检查,因此它将仅初始化一次列表.但是可以肯定的是,必须有一种更容易/更清洁/更好的方式来做到这一点吗?

It works alright; each bean is defined in its own applicationContext, and then I retrieve them by name. But... when do I call loadChildren()? So far, I'm doing it in the first line of each one of my methods. Since there is a null-check, it will initialize the list only once. But surely, there must be an easier/cleaner/better way of doing this?

我认为我不能在我的applicationContext中使用init-method="loadChildren"属性,因为如果我的主bean在所有子项都被加载之前就被加载,那么它将失败.我无法控制加载顺序.或者可以吗?

I don't think I can just use the init-method="loadChildren" property in my applicationContext, because then it would fail if my main bean is being loaded before all the children have been... and I can't control the loading order. Or can I?

这来自我的web.xml文件:

This is from my web.xml file:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
    /WEB-INF/application-context/applicationContext-*.xml
    ,classpath*:WEB-INF/application-context/applicationContext-children.xml
  </param-value>
</context-param>

((我们使用" classpath *表示法"来加载每个 applicationContext-children. JAR中的xml文件).如果我颠倒顺序并将子XML放在主XML之前,是否可以确保将按特定顺序加载子XML?无论我们使用哪种版本的应用服务器?

(We use the "classpath* notation" to load every applicationContext-children.xml file from within the JARs). If I invert the order and place the children XML before the main ones, would it ensure they will be loaded in that specific order? No matter what version of what application server we use?

我还看到了 @PostConstruct批注 如果可以将其添加到我的loadChildren方法中,将很有用.但是什么时候才能被调用呢?我读到它是在注入完成之后,但是...仅适用于当前的bean,对吗?是否不能确保所有其他bean都已加载?

I've also seen a @PostConstruct annotation which would be useful if I could add it to my loadChildren method. But when would it be called then? I've read that it's after the injections have been done, but... only for the current bean, right? It doesn't ensure that all the other beans are already loaded?

还有其他选择吗?

推荐答案

Spring可以为您做到这一点:

Spring can do this for you:

@Component
public class MyComponent {
    @Autowired
    private final List<IChildren> children;

    ...
}

这将自动实现除实现IChildren之外的所有功能.

That will autowire in everything than implements IChildren.

这篇关于如何(何时)初始化需要访问运行时才知道的其他bean的Spring bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆