tags:

views:

84

answers:

3

So here's the scenario:

I have a Spring XML configuration with some lazy-beans, some not lazy-beans and some beans that depend on other beans. Eventually Spring will resolve all this so that only the beans that are meant to be created are created.

The question: how can I programmatically tell what this set is?

When I use context.getBean(name) that initializes the bean. BeanDefinition.isLazyInit() will only tell me how I defined the bean.

Any other ideas?

ETA:

In DefaultListableBeanFactory:

public void preInstantiateSingletons() throws BeansException {
    if (this.logger.isInfoEnabled()) {
        this.logger.info("Pre-instantiating singletons in " + this);
    }

    synchronized (this.beanDefinitionMap) {
        for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
            String beanName = (String) it.next();
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
                    if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
                        getBean(beanName);
                    }
                }
                else {
                    getBean(beanName);
                }
            }
        }
    }
}

The set of instantiable beans is initialized. When initializing this set any beans not in this set referenced by this set will also be created. From looking through the source it does not look like there's going to be any easy way to answer my question.

+1  A: 

Perhaps

ApplicationContext.getBeanDefinitionNames()

Note that there is no (decent) way to determine which beans will be instantiated and which won't. If you are using ApplicationContextAware, you get access to all the beans at runtime, which makes this unpredictable.

Bozho
Unfortunately that still gives the entire set of definied beans.
cyborg
I don't understand what "beans that are meant to be created" means. All beans are meant to be created.
Bozho
lazy-init beans are not created unless required.
cyborg
and isLazyInit() doesn't return whether the bean is lazy?
Bozho
Yes, but it doesn't say whether or not the bean was created - some of the lazy beans will have been created, some will not.
cyborg
it can't really know which will get created. What if you use `ApplicationContextAware`, get the app context and get the bean programatically?
Bozho
Getting the bean programmatically instantiates it if it isn't yet instantiated. The basic problem I've got is that I can't really reconstruct the dependency graph from the `BeanDefinition` s to figure out which lazy-init beans have been initialiszed. It is looking like I'm going to have to do something at the point of initialization in the bean itself - which I wanted to avoid because I don't have access to do this for all instances of the beans. It will partially solve my problem though.
cyborg
A: 

So far my solution is:

  1. Create ExtendedApplicationContext implementing ApplicationContextAware
  2. Have the beans call initialized(this) on a static instance of ExtendedApplicationContext
  3. Use this set plus the set of all bean definitions that are not singletons, abstract or lazy-initialized to create the set of intialized beans in ExtendedApplicationContext

Any better suggestions are welcome.

cyborg
A: 

This is probably the best way, using a BeanPostProcessor:

public class IsIntializedBeanPostProcessor implements BeanPostProcessor {

    private Set<String> initializedBeanNames = new HashSet<String>();

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        initializedBeanNames.add(beanName);
        return bean;
    }

    public Set<String> getInitializedBeanNames() {
        return initializedBeanNames;
    }

}

Then all you have to do is include this as a bean somewhere in the Spring config in order for it to work.

cyborg