spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.26k stars 37.98k forks source link

Doc: BeanPostProcessor and lazy-init [SPR-2946] #7632

Closed spring-projects-issues closed 12 years ago

spring-projects-issues commented 17 years ago

Karl Moore opened SPR-2946 and commented

I'm not sure if this is a documentation issue or code.

Basically how is a BeanPostProcessor supposed to act if its been marked as lazy-init="true"? At the moment with an ApplicationContext, the lazy-init is ignore, with BeanFactory respected. The documentation does hint at this but its not very clear.

Quote from the documentation.

It is important to know that a BeanFactory treats bean post-processors slightly differently than an ApplicationContext. An ApplicationContext will automatically detect any beans which are defined in the configuration metadata which is supplied to it that implement the BeanPostProcessor interface, and register them as post-processors, to be then called appropriately by the container on bean creation. Nothing else needs to be done other than deploying the post-processors in a similar fashion to any other bean. On the other hand, when using a BeanFactory implementation, bean post-processors explicitly have to be registered, with code like this:

Note: You typically don't want to have BeanPostProcessors marked as being lazily-initialized. If they are marked as such, then the Spring container will never instantiate them, and thus they won't get a chance to apply their custom logic. If you are using the 'default-lazy-init' attribute on the declaration of your \ element, be sure to mark your various BeanPostProcessor bean definitions with 'lazy-init="false"'.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-extension-bpp


Affects: 2.0.1

Referenced from: commits https://github.com/spring-projects/spring-framework/commit/30751c9b0ae49a980ef548b1a8ab83d11f5c7fd1

spring-projects-issues commented 17 years ago

Karl Moore commented

Originally came from here. http://forum.springframework.org/showthread.php?t=32473

spring-projects-issues commented 17 years ago

Juergen Hoeller commented

The post-processor detection behavior was different in the 2.0 milestones; it changed back close to the original behavior for the 2.0 release candidates. That comment in the documentation seems to date back to the milestones... I'll make sure to clarify this for 2.0.2.

Juergen

spring-projects-issues commented 17 years ago

Juergen Hoeller commented

Removed the outdated note from the documentation.

spring-projects-issues commented 16 years ago

Winarto commented

I don't know whether I post this in the right place or not, but I still have problem with PropertyPlaceholderConfigurer which implements BeanFactoryPostProcessor.

What I'm trying to do is to configure Jasypt's EncryptablePropertyPlaceholderConfigurer which will read my encrypted DB properties file. However I need the EncryptablePropertyPlaceholderConfigurer not to be initialized upon initialization of the web application because the Password to decrypt will provided by system admin through web.

Following is my applicationContext.xml:

\<?xml version="1.0" encoding="UTF-8"?> \<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> \ \ \ \ \

<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor" lazy-init="true">
    <property name="config" ref="webPBEConfig"/>
</bean>

<bean id="webPBEConfig" class="org.jasypt.encryption.pbe.config.WebPBEConfig" lazy-init="true">
    <property name="validationWord" value="jasypt"/>
    <property name="name" value="Super Password"/>
</bean>

 <!--datasource and transaction management configuration -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" lazy-init="true">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<!-- iBatis configuration -->

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" lazy-init="true">
    <property name="configLocation" value="classpath:com/lifeisgreat/lifehub/api/dao/sqlmap/sqlmap-config.xml"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate" lazy-init="true">
    <property name="sqlMapClient" ref="sqlMapClient"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

\

The problem comes when the bean factory tries to initialized org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer even I have put lazy-init="true" because it will try to read my encrypted DB properties file and the password to decrypt is still not given.

Can anyone enlighten me how to "postpone" the BeanFactoryPostProcessor initialization?

Cheers, Winarto

spring-projects-issues commented 14 years ago

Grzegorz Grzybek commented

I might be wrong, bu I've checked many times - the reference documentation, section 3.8.2 is still wrong on the subject of Bean(Factory)Postprocessors and lazy-init. The section:

As with BeanPostProcessors, you typically do not want BeanFactoryPostProcessors marked as lazy-initialized. If they are marked as such, the Spring container never instantiates them, and thus they cannot apply their custom logic. If you use the default-lazy-init attribute on the declaration of your \ element, be sure to mark your various BeanFactoryPostProcessor bean definitions with lazy-init="false".

is referred to in http://www.blackbeltfactory.com/QuestionnaireDefDisplay.wwa?questPublicId=1712 in one question which (I think) is wrong.

Assuming the "Spring container" is ApplicationContext (on the basis of the preceeding paragraph), then both BeanPostProcessors and BeanFactoryPostProcessors will be instantiated regardless of the "lazy-init" value, because;

  1. AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) will invoke:
nonOrderedPostProcessors.add(*getBean*(postProcessorName, BeanFactoryPostProcessor.class))
  1. AbstractApplicationContext.registerBeanPostProcessors(ConfigurableListableBeanFactory) will invoke:
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
    BeanPostProcessor pp = *beanFactory.getBean*(ppName, BeanPostProcessor.class);
    nonOrderedPostProcessors.add(pp);
    if (pp instanceof MergedBeanDefinitionPostProcessor) {
        internalPostProcessors.add(pp);
    }
}

So even for lazy-init="true" for both BPP and BFPP the ApplicationContext will perform bf.getBean() thus instantiating them.

Leaving the note in reference documentation might be confusing...

spring-projects-issues commented 13 years ago

Oliver Drotbohm commented

Removed my comment as it was invalid actually.