Announcement Announcement Module
Collapse
No announcement yet.
Simple configuaration question Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Simple configuaration question

    At least I think its simple. I have a bean that I expect certain properties set on construction. i.e String query,String delimiter,PropertiesFile propertiesFile. The propertiesFile can be configured as a standard reference bean however how would you go configuring the query and delimiter properties as the values of these are determined at runtime?

    Thanks

    Sonik

  • #2
    Use a factory to retrieve the values dynamically and create instantiate the values for you - see org.springframework.beans.factory.FactoryBean.

    Comment


    • #3
      Not quite sure how this would work as I would imagine even with a factory class you still need to somehow pass in the variable values for the delimiter and query properties.

      The way I have got round the problem based on the following config file is :

      config file is :
      Code:
      <bean id="applicationProps" class="com.aCompany.app.util.PropertiesFile">
         <constructor-arg type="String"><value>PropertiesFile</value></constructor-arg>
      </bean>
      
      <bean id="flexivarDAO" class="com.aCompany.app.dao.Query" singleton="false">
         <property name="propFile"><ref bean="applicationProps"/></property>
      </bean>
      The code is :
      Code:
      Query flex = &#40;FlexivarQuery&#41;ctx.getBean&#40;"flexivarDAO"&#41;;
      flex.setDelimiter&#40;"|"&#41;;
      flex.setQuery&#40;queryStr&#41;;
      resultset = flex.runQuery&#40;&#41;;
      As you can see I programatically set the values for the variable properties. I wasn't sure whether this is best practice or not though.

      If this is not good could you explain how you would do it with the factory class you mention?

      Many Thanks

      Sonik

      Comment


      • #4
        The factory class can be aware of the code and inject the properties as you did before just it will be called by Spring. Read the javadocs and see the article on Sprin web sites about managing bean instances - a good explanation is also inside the reference documentation.

        If you store the properties inside property files then you can use a PropertyPlaceHolder to read replace them at runtime. See the examples within the distribution or the reference documentation.

        Comment


        • #5
          By taking this approach doesn't it make it dependant on the Spring Framework. I was under the impression code should be decoupled as much as possible.

          Comment


          • #6
            Well, not really, since you are injecting the properties values into the bean and not the bean it self, you are not coupling anything.

            However you are using a convinience function provided by Spring, which means if you wanna scrap spring in future, you need to write your own code to read the properties values and pass them into the bean.

            so it got nothing to do with code coupling but rather do you want to write the code yourself or use a prebuilt mechanism that requires no coding.

            Its the same with all the convinience methods and classes etc provided by Spring isn't it?

            Personally, I see nothing wrong with this.

            Comment


            • #7
              Why is it okay ...

              ... to say we are providing a lightweight framework that will not change the code its users write, and then tell them to write classes that would have to be recoded before they would run anywhere else? This is not the way to promote code reuse.



              I believe the original poster is asking a reasonable question. Having to instantiate wrappers, factories, or a combination of both, just to get one bean working and read a properties file --? And we say that saves coding? Hmmm. Let's review...

              The original problem was simple: want to read a properties file, using a dynamically-chosen delimiter. If we put the delimiter in a properties file...oh, wait, we're back to the original problem, except now we have TWO properties files. And we still haven't determined the delimiter at runtime. Of course he's stuck hard-coding the delimiter; hard-coding is an easier solution, and a properties file is only one step shy of hard-coding, anyway.

              Comment


              • #8
                You might consider making the delimiter and query string as part of the runQuery method call. That will make your object less stateless. If you have to set those other properties at runtime before running runQuery then your code won't be threadsafe.

                Comment


                • #9
                  Hey --

                  Good point.

                  Thread safety is a whole 'nother can of worms, isn't it.

                  It's enough to make my leetle head spin, and all the guy wanted was to set a delimiter and read a file.

                  I'm thinking this framework may not be useful for my project. These are some very basic problems.

                  Comment


                  • #10
                    Hi All,
                    Maybe I wasn't clear about what I was trying to do. The main problem is how to set the properties of an object, the values of which are only known at runtime, when instantiating it through the spring framework.

                    If I have the following class def :

                    public Class Query {
                    String query;
                    String delimiter;
                    PropertiesFile props;
                    }

                    When the object is created I want all of the properties set as none of the operations are valid unless all have valid values. If we were not using Spring this would simply be a constructer with the the three properties as constructer arguments which could be determined at runtime. With spring I have to create a default constructer with no parameters and then set the properties via injection. This is fine for properties that I have a value for such at the properties file. The problem is the dealing with those properties (query and delimiter) whose values are only going to be known at runtime. I have tried looking at the documentation several times and not really found what I need to do. As I mentioned in my previous post I have programatically set the properties at runtime. Why would this not be thread safe as each invocation of this object creates a new instance i.e its not a singleton class. By passing the delimiter and query properties to the runQuery method of the object I can only set the properties of the object when the runQuery method is run which to me sounds like bad practice if you need the values set at time of instantiation. But I agree this would get round the problem

                    I hope that makes sense. If you mention what page you have seen this in the reference manual, I would be keen to follow it up.

                    Many Thanks

                    Sonik

                    Comment


                    • #11
                      Originally posted by soniks
                      Maybe I wasn't clear about what I was trying to do. The main problem is how to set the properties of an object, the values of which are only known at runtime, when instantiating it through the spring framework.
                      This is a common problem that pops up. People want to do something like:

                      Code:
                        applicationContext.getBean("myBean", new Object[] { delimiter, query });
                      And have Spring use dependency injection using those runtime values.

                      Unfortunately this functionality doesn't exist in a usable form. There is a JIRA issue against it, and the developers are considering implementing it.

                      To make this work the way you want is complicated. Spring doesn't handle runtime property injection very well. Its designed to deal with objects whose configuration (including scalar properties) are determined at startup.

                      BUT, your original suggestion:
                      Code:
                      Query flex = (FlexivarQuery)ctx.getBean("flexivarDAO");
                      flex.setDelimiter("|");
                      flex.setQuery(queryStr);
                      resultset = flex.runQuery();
                      Will work just fine so long as your flexivarDAO bean has singleton=false in your context. Basically you create a new copy per invocation. That would guarentee thread safety. What you probably want is to only create one DAO for each combination of delimter and queryStr. Basically a custom factory. So you could do something like:

                      Code:
                        public interface FlexivarQueryFactory {
                          public FlexivarQuery getFlexivarQuery(String delimiter, String queryStr);
                        }
                      And in your business code:
                      Code:
                        setFlexivarQueryFactory(FlexivarQueryFactory flexivarQueryFactory) {
                          this.flexivarQueryFactory = flexivarQueryFactory;
                        }
                      
                        Query flex = flexivarQueryFactory.getFlexivarQuery("|", queryStr);
                        flex.runQuery();
                      A custom factory would allow you to cache your DAOs. Or you could use your original code and use new. Either way. You would inject the factory into your business object. You could change the implementation of your factory without affecting your DAO or your business code.

                      Caching your DAOs and initializing as much of your DAO as possible in Spring is not trivial. A custom factory as I've implemented it so that the static pieces of configuration can be done in a Spring file, and the other properties determined at runtime are set before the init-method or afterPropertiesSet are executed is complicated. See this thread for more detail.

                      With spring I have to create a default constructer with no parameters and then set the properties via injection.
                      In general you don't have to use setter injection, you can use constructor injection. Section 3 of the reference manual has more information. However, constructor injection doesn't help you if your constructor parameters are determined at runtime, like your case.

                      Why would this not be thread safe as each invocation of this object creates a new instance i.e its not a singleton class.
                      If its not a singleton class, then there isn't a problem. In general I try and create only so many objects as I need, rather than one per request. But some point you have to create some classes locally for each request. Its a matter of what works for the situation.

                      Originally posted by EvaluatingSpring
                      ... to say we are providing a lightweight framework that will not change the code its users write, and then tell them to write classes that would have to be recoded before they would run anywhere else? This is not the way to promote code reuse.
                      It doesn't say exactly that. It says that your code shouldn't depend on Spring APIs. And I believe they are referring to the wiring and configuration of your code. Obviously if you are using Spring's JDBC abstraction or MVC framework you'll need to use their APIs. But designing your code as decoupled from other services (using dependency injection), using AOP to handle cross cutting concerns (like transactions) makes it more reusable and testable. The HUGE number of convenience classes Spring creates shows that sometimes you do have to use utility classes to help you along. Sometimes you have specific needs Spring doesn't meet, so you write these utility classes yourself. The custom factory is an example. But if you write to interfaces, you can replace these custom objects with non-Spring versions if the need arises.

                      Originally posted by EvaluatingSpring
                      I believe the original poster is asking a reasonable question. Having to instantiate wrappers, factories, or a combination of both, just to get one bean working and read a properties file --? And we say that saves coding? Hmmm. Let's review...
                      Initialization of objects using runtime properties has its issues in Spring. In order to do it with complete decoupling and flexibility so you can apply AOP to your DAOs and whatever else the Spring container gives you, yes you have to write additional code.

                      Spring is a disruptive technology. The Spring website states "Spring should be a pleasure to use". Unfortunately until you really understand what they mean by this, it often isn't. And when YOU get comfortable using Spring, you coworkers chime in: "that doesn't look easier, it looks more complicated".

                      If Spring magically when away, but somehow you were forced to make your code decoupled and unit testable much in the same way Spring encourages, you'd probably encounter the same issues. The issue is not with Spring. Its with the design patterns it utilizes. Once you use those design patterns, Spring is ONE way to wire your system together. Given the fact that alternative would be a gigantic pile of wiring code, Spring is indeed better.

                      Comment

                      Working...
                      X