I\'m facing an issue trying to define a context hierarchy using AnnotationConfigApplicationContext
.
The problem is when defining a module context insid
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>
I also run into a similar problem and after some research I found the following approach using a constructor from AnnotationConfigApplicationContext that allows to set the a hierarchy between contexts
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parentContext);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(lbf);
context.register(annotatedClass1.class, annotatedClass2.class);
context.refresh();
What I did was the following:
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance("classpath:beanRefContext.xml");
BeanFactoryReference parentContextRef = locator.useBeanFactory("ear.context");
ApplicationContext parentContext = (ApplicationContext) parentContextRef.getFactory();
childContext.setParent(parentContext);
And guess what, it worked :)
PS: If anyone knows how to replace the classpath:beanRefContext.xml with an @Configuration class, please let us all know.
Don't use XML for the child context. Use ctx.setParent then ctx.register. Like this:
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;
}
}
I run into the same problem,
Another possibility is to extend AnnotationConfigApplicationContext and add just the required constructor or build the context programmatically, if you are instantiating the AnnotationConfigApplicationContext from java.