Bivas Bivas - 20 days ago 5
Java Question

AnnotationConfigApplicationContext and parent context

I'm facing an issue trying to define a context hierarchy using

AnnotationConfigApplicationContext
.

The problem is when defining a module context inside
beanRefContext.xml
and setting the 'parent' property with another context (XML/Annotated based).

Example:

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
}


Module B application context fails to find bean defined in module A application context.

From looking at the code of
AnnotationConfigApplicationContext
it seems that the scanning process doesn't use the parent as a reference to resolve beans.

Is there something I'm doing wrong or my attempt to create a hierarchy is impossible with annotation configuration?

Answer

The problem stems from the fact that the constructor of the AnnotationConfigApplicationContext does the scan. Thus the parent is not set at this stage, it is only set after the scan is done as the parent is set by a property - thus the reason why it does not find your bean.

The default AnnotationConfigApplicationContext bean does not have a constructor that takes a parent factory - not sure why.

You can either use the normal xml based application context and configure your annotation scanning in there or you can create a custom fatory bean that will do create the annotation application context. This would specify the parent reference and then do the scan.

Take a look at the source...

The factory would look like this:

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;
    }
}

And your bean definition:

<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>