Page 1 of 2 12 LastLast
Results 1 to 10 of 22

Thread: How does really work bean initialization???

Hybrid View

  1. #1
    Join Date
    Mar 2005
    Location
    Madrid, Spain
    Posts
    71

    Unhappy How does really work bean initialization???

    Dear members,

    I have a bean propertiesManager for defining the properties of my project, so I want to use this bean in order to get some constant values on other beans. I am setting the lazy-init to false in order to have the garantee this bean will be first instanciated.

    Code:
     
      <bean id="propertiesManager"
            class = "com.schinvest.util.PropertiesManager"
            lazy-init = "false"
            singleton ="true"
        >
            <constructor-arg index="0">
                <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                    <property name="location">
                        <value>classpath:lra.properties</value>
                    </property>
                </bean>
            </constructor-arg>
            <constructor-arg index="1">
                <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                    <property name="location">
                        <value>classpath:lra_testCustom.properties</value>
                    </property>
                </bean>
            </constructor-arg>
        </bean>
    Now I want to define a bean that uses such properties defined on the PropertiesManager:

    Code:
     
    <bean id="positionBatch"
         class="com.schinvest.lra.business.batch.position.PositionBatchImpl"
            singleton = "true" depends-on="propertiesManager">
            <property name="propertiesManager">
                <ref local="propertiesManager"/>
            </property>
        </bean>
    on the PositionBatchImpl I have the following declaration that produces a NullPointerException:

    Code:
     
    public class PositionBatchImpl extends AbstractPositionBatch {
        private final String XML_EXT = propertiesManager.getProperty(LraPty.XML_EXT);
    }
    I have defined the attribute propertiesManager and its getter/setter method on the coresponding abstract class.

    If I run under junit my program I get the following initialization errror on the constant definition.

    Code:
     
    [testApplicationContext.xml]: Instantiation of bean failed; 
     nested exception is org.springframework.beans.FatalBeanException: 
     Could not instantiate class 
    [com.schinvest.lra.business.batch.position.PositionBatchImpl]; constructor 
    threw exception; nested exception is java.lang.NullPointerException: null
    org.springframework.beans.factory.BeanCreationException: Error creating 
    bean with name 'positionBatch' defined in class path resource 
    [testApplicationContext.xml]: Instantiation of bean failedError creating bean 
    with name 'positionBatch' defined in class path resource 
    [testApplicationContext.xml]: Instantiation of bean failed; nested exception 
    is org.springframework.beans.FatalBeanException: Could not instantiate class 
    [com.schinvest.lra.business.batch.position.PositionBatchImpl]; constructor 
    threw exception; nested exception is java.lang.NullPointerException: null
    org.springframework.beans.factory.BeanCreationException: Error creating 
    bean with name 'positionBatch' defined in class path resource 
    [testApplicationContext.xml]: Instantiation of bean failed
    The error comes on the testing class:

    Code:
     
    public class TestPositionBatchImpl extends
            AbstractDependencyInjectionSpringContextTests {
    protected void onSetUp() throws Exception {
             this.batch = (PositionBatchImpl) (applicationContext
             .getBean("positionBatch"));
            super.onSetUp();
        }
     }
    so, even using lazy-init and depends-on to force that really propertiesManager bean has to be initialized before, that doesn't happen. I am for sure loosing somthing, but I guess it should be a way to do make this kind of dependence.

    I am planning to convert PropertiesManager into class with static method and attributes, but I don't know if this is a good desing and if it works.

    Thanks in advance,

    David
    ______________________
    David Leal

  2. #2
    Join Date
    Mar 2005
    Location
    San Francisco, CA
    Posts
    114

    Default

    When your positionBatch bean is initialized it get constructed first and then the setters get called. So your field initializer code is being executed when the object is being constructed, but before the bean properties have been set. That is why the propertiesManager property of you bean is null even though it has been created.

    Have you looked at the PropertyPlaceHolderConfigurer? That seems like it does what you are looking for.

  3. #3
    Join Date
    Mar 2005
    Location
    Madrid, Spain
    Posts
    71

    Default

    Dear dgynn and other,

    Thanks for your interest on my problem. The reason is what you have said, but it is hard for me to understand. The propertiesManager bean is a singleton, and have to be instanciated first because it is not lazy and the positionBatch bean depends on this bean, so when I want to initialize positionBatch bean, the propertiesManager bean should be instanciated before and it is a singleton, so it should take this, but it doesn't happen because the rare call back mechanism on the bean initialization process.

    About your suggestion using PropertyPlaceHolderConfigurer, I think it is for different purpose. This implementation allow you to define properties in the Ant way, that is: ${property}, so it looks on the property file and replace this token by its value on the applicationContext.xml file. Using this solution, you have add a property definition on the positionBatch definition in order to set it current value. If you want to share this property by other class you have to add this property on all possible bean definition.

    The idea behind the PropertiesManager is to have on ONE PLACE all possible project definitions (I am implemeting a batch process, so I have to controll a lot or parameters), in such way that you can define the default properties of the project on the lra.properties file and for a particular build or just for working in a team you can define your lra_testCustom.properties, that overrides the default definition of the properties. So the lra.properties and the applicationContext.properties are more control version stable. That is my idea.

    Now I guess I explained more my problem, please let me know if you have any other suggestion about this.

    Thanks in advance,
    ______________________
    David Leal

  4. #4
    Join Date
    Aug 2004
    Location
    u.s.a
    Posts
    399

    Default

    I agree with dgynn, its the field initialization which comes before the setter injection. To experiment you can move the field init into an actual initialization method which would get invoked in the 'afterPropertiesSet' lifecycle stage, for example:
    Code:
    <bean id="positionBatch"
         class="com.schinvest.lra.business.batch.position.PositionBatchImpl"
            singleton = "true" depends-on="propertiesManager" init-method="init">
            <property name="propertiesManager" ref="propertiesManager"/>
    </bean>
    
    public class PositionBatchImpl extends AbstractPositionBatch {
        private String XML_EXT;
        ...... other fields and setters....
        public void init(){
            XML_EXT = propertiesManager.getProperty(LraPty.XML_EXT);
        }
    }

  5. #5
    Join Date
    Mar 2005
    Location
    San Francisco, CA
    Posts
    114

    Default

    Yeah, using the init-method is the right point in the lifecycle to ensure the propertiesManager property has been set. Also, you won't need the lazy-init and depends-on properties.

    Two more suggestions for you...

    The PropertiesFactoryBean can take a list of property file locations. So you could do this.
    Code:
    <bean id="propertiesManager" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:lra.properties</value>
                <value>classpath:lra_testCustom.properties</value>
            </list>
        </property>
    </bean>
    And then change your abstract class's propertiesManager to a java.util.Properties object. Properties in the second file will override properties in the first file.

    Also, you might want to consider an abstract bean definition if you are going to have multiple beans that access the properties manager.

    Code:
    <bean id="abstractBatchDefinition" abstract="true" init-method="init">
        <property name="propertiesManager">
            <ref local="propertiesManager"/>
        </property>
    </bean>
    
    <bean id="positionBatch" parent="abstractBatchDefinition" class="com.schinvest.lra.business.batch.position.PositionBatchImpl">
    </bean>

  6. #6
    Join Date
    Mar 2005
    Location
    Madrid, Spain
    Posts
    71

    Default

    About your first suggestion:
    Quote Originally Posted by dgynn
    The PropertiesFactoryBean can take a list of property file locations. So you could do this.
    Code:
    <bean id="propertiesManager" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:lra.properties</value>
                <value>classpath:lra_testCustom.properties</value>
            </list>
        </property>
    </bean>
    And then change your abstract class's propertiesManager to a java.util.Properties object. Properties in the second file will override properties in the first file.
    That was my first approach, but I have found two problems:
    - The toString() method for Properties, doesn't separate the information
    between default properties (new Properties(properties)) and the current properties.
    - Before setting the default and current properties, I need to parse some values for considering the spetial case when a property value represents
    the system property, for example if my tmp.dir has the value java.io.tmpdir.
    I want the property tmp.dir stores the value of java.io.tmpdir, that is the
    result of: System.getProperty("java.io.tmpdir"). Any way I will try to check this point again, probably I did some mistake.

    Also, you might want to consider an abstract bean definition if you are going to have multiple beans that access the properties manager.

    About your second suggestion, I took into account, but just for simplify the
    sample code, I have omitted it, thank any way.
    ______________________
    David Leal

  7. #7
    Join Date
    Mar 2005
    Location
    Madrid, Spain
    Posts
    71

    Default

    Quote Originally Posted by dgynn

    The PropertiesFactoryBean can take a list of property file locations. So you could do this.
    Code:
    <bean id="propertiesManager" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:lra.properties</value>
                <value>classpath:lra_testCustom.properties</value>
            </list>
        </property>
    </bean>
    And then change your abstract class's propertiesManager to a java.util.Properties object. Properties in the second file will override properties in the first file.
    I prefer to use delegation with the Properties because I would like to add some additional behaviour, I am planning to add getIntProperty, getBoolProperty, getFileProperty, for example. At this point a possible solution would be to extends the Properties, but I don't know exactly how to use your solution with this. Any way I am going to think about that.

    Thanks,
    ______________________
    David Leal

  8. #8
    Join Date
    Mar 2005
    Location
    Madrid, Spain
    Posts
    71

    Default

    Quote Originally Posted by jbetancourt
    I agree with dgynn, its the field initialization which comes before the setter injection. To experiment you can move the field init into an actual initialization method which would get invoked in the 'afterPropertiesSet' lifecycle stage, for example:
    Code:
    <bean id="positionBatch"
         class="com.schinvest.lra.business.batch.position.PositionBatchImpl"
            singleton = "true" depends-on="propertiesManager" init-method="init">
            <property name="propertiesManager" ref="propertiesManager"/>
    </bean>
     
    public class PositionBatchImpl extends AbstractPositionBatch {
        private String XML_EXT;
        ...... other fields and setters....
        public void init(){
            XML_EXT = propertiesManager.getProperty(LraPty.XML_EXT);
        }
    }
    Good solution, but you have to pay a syntax price. Such variable can't be anymore final, :-((((

    Thanks, I would take into account it,

    David
    ______________________
    David Leal

  9. #9
    Join Date
    Aug 2006
    Location
    Now Germany, previously Ukraine
    Posts
    1,546

    Default

    I guess the easiest way to solve your problem is to switch from setter injection to constructor parameter injection for PropertyManager in the PositionBatch class.

    Regards,
    Oleksandr

  10. #10
    Join Date
    Aug 2007
    Posts
    8

    Question Bean Creation and Initialization

    Hi,

    I know that setters are set after Bean Creation, but during Bean Creation, what happens to properties of the class?

    Suppose there is boolean var - will it be set to false?
    and what about any Map variable - set to null / initialized (by reading from database )?
    (Note : by default, maps are lazily loaded)

    And, is order correct - 1) Bean Creation 2) Setters are called 3) Bean Initialization
    If not, what is the correct order?

    Actually, I want to instantiate a Map property of a class depending on the value of a boolean variable of the same class after setting it from applicationContext.xml.
    How to do it?

    Thanks,
    Sucheta.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •