【问题标题】:AnnotationConfigApplicationContext and parent contextAnnotationConfigApplicationContext 和父上下文
【发布时间】:2011-05-20 20:05:35
【问题描述】:

我在尝试使用 AnnotationConfigApplicationContext 定义上下文层次结构时遇到问题。

问题在于在 beanRefContext.xml 中定义模块上下文并使用另一个上下文(基于 XML/Annotated)设置“父”属性时。

例子:

模块 A 中的 beanRefContext.xml

类路径:db-context.xml列表> 属性> 豆>

db-context.xml

com.example.model列表> 属性> 属性> 豆>

模块 B 中的 beanRefContext.xml

com.example.dao列表> 豆>

FooHibernateDao

类 FooHibernateDao 实现 FooDao { @自动连线 @Qualifier("sessionFactory") 私有 SessionFactory 会话工厂; // CRUD 方法 }

模块 B 应用程序上下文找不到在模块 A 应用程序上下文中定义的 bean。
AnnotationConfigApplicationContext的代码来看,扫描过程似乎没有使用父级作为参考来解析bean。

是不是我做错了什么,或者我尝试通过注释配置来创建层次结构是不可能的?

【问题讨论】:

  • 这应该可以正常工作。您能否举例说明未找到的 bean 定义,以及子上下文如何尝试解决它?
  • db-context.xml 在其中配置了数据源和 sessionFactory(简单的 XML bean 配置),但是当尝试在 module_B 应用程序上下文中自动装配它们时,它说它找不到 sessionFactory 来满足 dao 依赖关系。
  • 请编辑您的问题,向我们展示相关组件。您的描述很好,但有一些细节使它无法正常工作。
  • @skaffman 我添加了组件,希望对您有所帮助

标签: java spring annotations


【解决方案1】:

问题源于 AnnotationConfigApplicationContext 的构造函数进行扫描。因此,在此阶段未设置父级,它仅在扫描完成后设置,因为父级由属性设置 - 这就是它找不到您的 bean 的原因。

默认 AnnotationConfigApplicationContext bean 没有采用父工厂的构造函数 - 不知道为什么。

您可以使用普通的基于 xml 的应用程序上下文并在其中配置您的注释扫描,或者您可以创建一个自定义的 fatory bean 来创建注释应用程序上下文。这将指定父引用,然后进行扫描。

看看源码...

工厂看起来像这样:

public class AnnotationContextFactory implements FactoryBean<ApplicationContext> {

private String[] packages;
private ApplicationContext parent;

@Override
public ApplicationContext getObject() throws Exception {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.setParent(parent);
    context.scan(packages);
    context.refresh();
    return context;
}

@Override
public Class<ApplicationContext> getObjectType() {
    return ApplicationContext.class;
}

@Override
public boolean isSingleton() {
    return true;
}

public void setPackages(String... args) {
    this.packages = args;
}

public void setParent(ApplicationContext parent) {
    this.parent = parent;
    }
}

还有你的 bean 定义:

<bean id="moduleB_ApplicationContext" class="za.co.test2.AnnotationContextFactory">
    <property name="parent" ref="moduleA_ApplicationContext" />
    <property name="packages">
        <list>
            <value>za.co.test2</value>
        </list>
    </property>
</bean>

【讨论】:

【解决方案2】:

不要将 XML 用于子上下文。 使用 ctx.setParent 然后 ctx.register。像这样:

public class ParentForAnnotationContextExample {

    public static void main(String[] args) {
        ApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentContext.class);

        AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
        childContext.setParent(parentContext);
        childContext.register(ChildContext.class); //don't add in the constructor, otherwise the @Inject won't work
        childContext.refresh();

        System.out.println(childContext.getBean(ParentBean.class));
        System.out.println(childContext.getBean(ChildBean.class));

        childContext.close();
    }

    @Configuration
    public static class ParentContext {
        @Bean ParentBean someParentBean() {
            return new ParentBean();
        }
    }

    @Configuration
    public static class ChildContext {
        @Bean ChildBean someChildBean() {
            return new ChildBean();
        }
    }

    public static class ParentBean {}

    public static class ChildBean {
        //this @Inject won't work if you use ChildContext.class in the child AnnotationConfigApplicationContext constructor
        @Inject private ParentBean injectedFromParentCtx;
    }
}

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,

    另一种可能性是扩展 AnnotationConfigApplicationContext 并仅添加所需的构造函数或以编程方式构建上下文,如果您要从 java 实例化 AnnotationConfigApplicationContext。

    【讨论】:

      【解决方案4】:

      我做了以下事情:

      BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance("classpath:beanRefContext.xml");
      BeanFactoryReference parentContextRef = locator.useBeanFactory("ear.context");
      ApplicationContext parentContext = (ApplicationContext) parentContextRef.getFactory();
      childContext.setParent(parentContext);
      

      你猜怎么着,它奏效了 :)

      PS:如果有人知道如何用@Configuration 类替换classpath:beanRefContext.xml,请告诉我们。

      【讨论】:

        【解决方案5】:

        我也遇到了类似的问题,经过一番研究,我发现以下方法使用 AnnotationConfigApplicationContext 中的构造函数,允许设置上下文之间的层次结构

        DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parentContext);
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(lbf);
        context.register(annotatedClass1.class, annotatedClass2.class);
        context.refresh();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-17
          • 1970-01-01
          相关资源
          最近更新 更多