Search code examples
javaspringinversion-of-control

How to set parent of current beanFactory in spring IOC


I was going through the spring IOC documentation and came across the following code snippet:

<bean name="messageBroker,mBroker,MyBroker" class="com.components.MessageBroker">
    <property name="tokenBluePrint">
        <ref parent="tokenService" />
    </property>
</bean>

As per the documentation, parent attribute of "ref" tag is used to refer the parent bean factory of the current bean factory, but to set the parent of a bean factory.

I have tried following code snippet. But still, I get the error.

    String[] xmlFies=new String[1];
    xmlFies[0]="applicationContext.xml";

    ClassPathXmlApplicationContext parentContext=new    ClassPathXmlApplicationContext("tokenConfiguration.xml");
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlFies);
    context.setParent(parentContext);
    context.getBeanFactory().setParentBeanFactory(parentContext.getBeanFactory());
    context.close();
    parentContext.close();

Error :

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageBroker' defined in class path resource [applicationContext.xml]: Can't resolve reference to bean 'tokenService' in parent factory: no parent factory available at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:360)

Am I missing something? Please have a look.


Solution

  • I believe the issue is that your child context is refreshing before the parent context is set.

    Here are the relevant constructors from ClassPathXmlApplicationContext:

    // this is the constructor that 'context' is using, and refresh is defaulted to true
    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }
    
    // the constructor that both others are calling
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            // you don't want to refresh until your parent context is set
            refresh();
        }
    }
    
    // the constructor I think you should use, it will set the parent first and then refresh
    public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }
    

    I would instead use the last constructor so that the parent context is set before refresh() is called.

    Like this:

    String[] xmlFies=new String[1];
    xmlFies[0]="applicationContext.xml";
    
    ClassPathXmlApplicationContext parentContext = new ClassPathXmlApplicationContext("tokenConfiguration.xml");
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlFies, parentContext);
    . . .