Home Articles

AnnotationConfigApplicationContext和父上下文

Asked
Viewed 1475 times
4

我正在尝试使用 AnnotationConfigApplicationContext 来定义上下文层次结构 .

问题是在 beanRefContext.xml 中定义模块上下文并使用另一个上下文(基于XML / Annotated)设置'parent'属性 .

例:

beanRefContext.xml in module A

<bean id="moduleA_ApplicationContext"  
      class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <property name="configLocations">
        <list>
            <value>classpath:db-context.xml</value>
        </list>
    </property>
</bean>

DB-的context.xml

<bean id="dataSource" 
      class="org.apache.commons.dbcp.BasicDataSource" 
      destroy-method="close"
      p:driverClassName="org.h2.Driver"
      p:url="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;TRACE_LEVEL_SYSTEM_OUT=2"/>

<!-- Hibernate Session Factory -->
<bean name="sessionFactory" 
      class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="useTransactionAwareDataSource" value="true"/>
        <property name="packagesToScan">
            <list>
                <value>com.example.model</value>
            </list>
        </property>
        <property name="hibernateProperties">
        <!-- hibernate props -->
        </property>
</bean>

beanRefContext.xml in module B

<bean id="moduleB_ApplicationContext" 
      class="org.springframework.context.annotation.AnnotationConfigApplicationContext" >
    <property name="parent" ref="moduleA_ApplicationContext"/>
        <constructor-arg>
            <list>
                <value>com.example.dao</value>
            </list>
        </constructor-arg>
</bean>

FooHibernateDao

class FooHibernateDao implements FooDao {
    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionsFactory;

    // CRUD methods
}

模块B应用程序上下文无法找到模块A应用程序上下文中定义的bean .
通过查看 AnnotationConfigApplicationContext 的代码,似乎扫描过程不使用父作为解析bean的引用 .

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

4 Answers

  • 6

    问题源于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>
    
  • 3

    不要将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;
        }
    }
    
  • 1

    我做的是以下内容:

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

    猜猜看,它 worked :)

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

  • 0

    我遇到了同样的问题,

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

Related