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开发者_Go百科 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.
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 :)
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.
If you have another bean to which it makes sense to add this responsibility (for example, an existing bean dealing with application lifecycle) you could have that bean implement ApplicationListener<ContextRefreshedEvent>
and do the sanity checking there. Otherwise I like @Costi's answer.
精彩评论