Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to specify to Spring that a bean should be used upon initialization and then immediately discarded?

Tags:

java

spring

I'm interested to know if there is an interface that I can use to tell Spring to start a particular bean up, invoke its initialization procedure (either as an InitializingBean via afterPropertiesSet(), or via an init-method, or some other way), and then throw it away.

My use case is a simple "sanity-checker" that will check the database for valid values upon startup for a web application. Although the overhead would be small for our particular bean, keeping that bean for all eternity in the application context is pointless, as once the bean had initialized, it is no longer needed.

I'm sure there are other use cases for this type of behavior, but I haven't found anything like this yet in Spring.

In particular, I'm looking for it in the Java variant of Spring, I have access to 3.x and up as needed.

EDIT: based on the accepted answer, the following is a simple hack to provide the solution:

public final class NullReturningBeanPostProcessor implements BeanPostProcessor {

    private List<String> beanNamesToDiscard = new ArrayList<String>();

    /**
     * Creates a new {@link NullReturningBeanPostProcessor} instance.
     */
    public NullReturningBeanPostProcessor() {
    super();
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (beanNamesToDiscard.contains(beanName)) {
        return null;
    }
    return bean;
    }

    public void setBeanNamesToDiscard(List<String> beanNamesToDiscard) {
    if (beanNamesToDiscard != null) {
        this.beanNamesToDiscard = beanNamesToDiscard;
    }
    }
}

Placing this bean post processor with the appropriate beans to discard in the application context will make them null, and eligible for garbage collection after they've been initialized. The bean configuration metadata, unfortunately, will still remain in the application context.

like image 502
MetroidFan2002 Avatar asked Jun 16 '11 17:06

MetroidFan2002


People also ask

How can we call a method after bean initialization in Spring?

Hello Friends, If you Want to call the method after your bean is initialize in spring you can use the following options. Use the afterProprtiesSet method. 2:- You can use the annotation @PostConstruct in your class. to enable this you need to define in your application context xml file.

Which attribute can we use while defining a bean to call a method just after bean instantiation?

Use init-method attribute.

Which of the following is the most suitable way to initialize the bean?

In spring you can initialize a bean by having the applicationContext. xml invoke a constructor, or you can set properties on the bean.

How are beans initialized in Spring?

Bean life cycle is managed by the spring container. When we run the program then, first of all, the spring container gets started. After that, the container creates the instance of a bean as per the request, and then dependencies are injected. And finally, the bean is destroyed when the spring container is closed.


2 Answers

To achieve this, I would make that bean implement BeanPostProcessor and then:

@Override
Object postProcessAfterInitialization(Object bean, String beanName)
    throws BeansException {
    return bean == this ? null : bean;
}

This should cause the ApplicationContext to discard it but only after it has performed the initialization steps.

Note that you also need to implement postProcessBeforeInitialization() and there just write return bean;.


Update: this does NOT work. But not due to MetroidFan2002's comment (see bellow), but due to another part of the JavaDoc:

ApplicationContexts can autodetect BeanPostProcessor beans in their bean definitions and apply them to any beans subsequently created.

So obviously you cannot apply a BeanPostProcessor to itself. Sorry for the false alarm :)

like image 132
Costi Ciudatu Avatar answered Nov 21 '22 05:11

Costi Ciudatu


You could use a MethodInvokingFactoryBean bean definition to execute a method on application context initialization. Though, you do have to be careful with dependencies if some beans need to be initialized before the method is invoked. The following would execute the checkDatabase method on the bean named sanityChecker after beanA, beanB and beanC are initialized:

<bean
    id="methodInvoker"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
    depends-on="beanA, beanB, beanC"
    lazy-init="false"
    p:singleton="false"
    p:target-method="checkDatabase"
    p:target-object-ref="sanityChecker"
/>

<bean
    id="sanityChecker"
    class="com.example.SanityChecker"
    lazy-init="true"
    scope="prototype"
/>

Since checkDatabase is a prototype, its lifecycle is not managed by the application context and should be garbage collected after initialization; that's something a unit test could prove out. methodInvoker might also need to be a prototype for checkDatabase to be garbage collected.

like image 21
Dan Cruz Avatar answered Nov 21 '22 03:11

Dan Cruz