Announcement Announcement Module
Collapse
No announcement yet.
How does really work bean initialization??? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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

  • #2
    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.

    Comment


    • #3
      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,

      Comment


      • #4
        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);
            }
        }

        Comment


        • #5
          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>

          Comment


          • #6
            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

            Comment


            • #7
              About your first suggestion:
              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.

              Comment


              • #8
                The solution I have found

                Dear members and readers,

                I am sending the solution I have found and it works:

                First setting on the applicationContext.xml file default lazy init to true, that is:
                Code:
                 
                <beans default-lazy-init="true">
                </beans>
                Now the definition of propertiesManager will be:

                Code:
                 
                   <bean id="propertiesManager"
                        class = "com.schinvest.util.PropertiesManager"
                        lazy-init = "false"
                        singleton ="true"
                    >
                            <property name="defaultProperties">
                                <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                                    <property name="location">
                                        <value>classpath:lra.properties</value>
                                    </property>                
                                </bean>
                            </property>
                            <property name="properties">
                                <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                                    <property name="location">
                                        <value>classpath:lra_testCustom.properties</value>
                                    </property>
                                </bean>                
                            </property>                
                    </bean>
                so the bean propertiesManager, is a singleton and with lazy-init=false (it is not really necessary)

                Now I have changed the definition of the class PropertiesManager, now the defaultProperties and properties will be static, with setter method non static, because otherwise the bean initialization doesn't work.

                Now comes the definition of positionBatch

                Code:
                <bean id="baseService" abstract="true" depends-on="propertiesManager"
                    >
                        <property name="propertiesManager">
                            <ref local="propertiesManager"/>
                        </property>
                    </bean>
                and

                Code:
                 
                <bean id="positionBatch"
                class="com.schinvest.lra.business.batch.position.PositionBatchImpl"
                singleton = "true" depends-on="propertiesManager"
                parent ="baseService">
                ....
                </bean>
                with this I can use, the following definition for the static final attribute on
                PositionBatchImpl:

                Code:
                private final String XML_EXT = propertiesManager
                            .getProperty("xml.ext");
                Thanks to all people,

                David

                Comment


                • #9
                  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,

                  Comment


                  • #10
                    Hello,

                    I have a LocalizedString bean in applicationContext.xml and I am setting a boolean variable(dealerSites) through applicationContext.xml and there is a map variable (values) in my class LocalizedString.

                    Now, the setter is called after schema update while map variable is being accessed in sessionFactory itself (via a call to getValues function), in which the value of dealersites is being assumed false.

                    As can be seen from the code, i want Map to be lazily loaded when dealerSites is true, which is not happening.

                    What is to be done? (I am attaching the code, name of file is - LocalizedString.java)

                    Thanks,
                    Sucheta.

                    Comment


                    • #11
                      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

                      Comment


                      • #12
                        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.

                        Comment


                        • #13
                          There is not Spring-specific in this case. It behaves like any other Java application. First object is created with appropriate constructor (even if object is created by factory method somewhere in that method constructor shall be called!) and all object fields are initialized by JVM according to Java Language Specification.
                          It means that all fields of non-primitive that have no explicit initializers and are not initialized by constructor are set to null, numeric fields to 0, boolean to false etc.

                          And only then Spring sets properties, apply post methods etc.

                          Regards,
                          Oleksandr

                          Originally posted by Sucheta24 View Post
                          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.

                          Comment


                          • #14
                            Continued...

                            Hi ,

                            Thanks for your reply.

                            But then as I checked in log - getValues method being called in AbstractEntityPersister by Dealers.java (another class). Whereas setter being called after that.
                            And there (in AbstractEntityPersister) map object being accessed assuming the value of boolean variable to be false.

                            I am attaching the code(LocalizedString.java) to make the point clear.

                            Thanks,
                            Sucheta.

                            Comment


                            • #15
                              Sorry, your attacment seems to be lost in space ...

                              Originally posted by Sucheta24 View Post
                              Hi ,

                              Thanks for your reply.

                              But then as I checked in log - getValues method being called in AbstractEntityPersister by Dealers.java (another class). Whereas setter being called after that.
                              And there (in AbstractEntityPersister) map object being accessed assuming the value of boolean variable to be false.

                              I am attaching the code(LocalizedString.java) to make the point clear.

                              Thanks,
                              Sucheta.

                              Comment

                              Working...
                              X