Announcement Announcement Module
Collapse
No announcement yet.
Generating Spring Bean Definitions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Generating Spring Bean Definitions

    I am working on a project in which I found myself writing almost the same bean definition over and over, even after using an abstract bean definition to pull out the common parts.

    Something like

    Code:
    <bean id="fooService" class="com.abc.service.impl.FooServiceImpl">
        <property name="dao">
            <bean class="com.abc.service.dao.FooDao"/>
        </property></bean>
    
    <bean id="barService" class="com.abc.service.impl.BarServiceImpl">
        <property name="dao">
            <bean class="com.abc.service.dao.BarDao"/>
        </property></bean>
    
    <bean id="blahService" class="com.abc.service.impl.BlahServiceImpl">
        <property name="dao">
            <bean class="com.abc.service.dao.BlahDao"/>
        </property></bean>
    So I wrote a class to generate bean definitions using Velocity. My definitions now look like

    Code:
        <bean class="com.abc.spring.DefineBeansViaVelocity">
            <property name="beanDefinitionContextFactory">
                <bean class="com.abc.spring.DataAccessBeanDefinitionContextFactory"/>
            </property>
            <property name="beanDefinitionTemplate">
                <value><![CDATA[
                    <bean id="${bean.entity}DAO" parent="abstractDAO" class="${bean.className}"/>
                ]]></value>
            </property>
            <property name="beansNeeded">
                <list>
                <value>com.abc.service.dao.impl.PersonDAOHibernate</value>
                <value>com.abc.service.dao.impl.BlahDAOHibernate</value>
                <value>com.abc.service.dao.impl.FrapDAOHibernate</value>
                <value>com.abc.service.dao.impl.SnarkDAOHibernate</value>
                <value>com.abc.service.dao.impl.SleepDAOHibernate</value>
                <value>com.abc.service.dao.impl.ZoomDAOHibernate</value>
                <value>com.abc.service.dao.impl.GarfDAOHibernate</value>
                <value>com.abc.service.dao.impl.ZevonDAOHibernate</value>
                </list>
            </property>
        </bean>
    The question is, is there a better approach? Is there interest in posting the classes that enable this, and if so, where should they go? There are additional details and improvements to be made.

  • #2
    What do you get from this approach that you don't get from the abstract parent bean? I can imagine some possible benefits to externalizing the list of beans to be defined, but I find it hard to come up with a common realistic use case.

    There are also potential issues with the implementation, e.g. most ApplicationContext implementations do not have an API to register a new BeanDefinition (it's easier to register a bean instance). I guess it might be possible to fix that as well, but I would be interested to understand more about the use case first.

    If you want to post some code I'm sure people will try it out, and you can guage the interest here before posting again on JIRA.

    Comment


    • #3
      The primary benefit is reducing duplication. The abstract bean lets you pull out common portions -- the part that is identical. What I see in the first example block of bean definitions above is a template:

      <code>
      <bean id="xXXService" class="com.abc.service.impl.XXXServiceImpl">
      <property name="dao">
      <bean class="com.abc.service.dao.XXXDao"/>
      </property>
      </bean>
      </code>


      Rather than copy/paste that many times, I'm trying to create a method that parameterizes the definition -- more than inheritance. One of the criticisms I am getting about Spring is that the file is too big/complicated with lots of repetition on similar definitions.

      You have many classes, all in the same package, for which bean definitions are required. A common naming scheme applies for all the beans. The beans share the same properties, but with slight (but consistent) variations on the property values.

      Comment


      • #4
        You can:
        1. Implement your own FactoryBean that has property:
        [code]<property name="xxxName" value="XXX"/></code>
        and create service bean initialized by dao bean based on this property value
        2. You can introduce your own namespace and handler for it that will simplify your configuration
        3. Also, you can look on BeanFactoryPostProcessor interface or @Configurable annotation

        Comment


        • #5
          i had the same situation, most of my typing was these spring config files. What i ended up doing was writing a DAOFactory & ServiceFactory. These classes have a lot of delegate methods, which take at a minimum the entity bean class. Optionally a service interface & implementation, and also a DAO interface & possibly implementation. Each one of those four methods is also duplicated with another one that takes a Map<String, Object> for dependencies. These have reduced my spring config to stuff like this:

          Code:
          //ultra generic service
          <bean id="PersonService">
              <constructor-arg value="com.test.model.Person" />
          </bean>
          
          // service with custom interface & impl
          <bean id="PhysicianService">
              <constructor-arg value="com.test.model.Physician" />
              <constructor-arg value="com.test.service.PhysicianService" />
              <constructor-arg value="com.test.service.PhysicianServiceImpl" />
          </bean>
          
          // service with custom interface, impl, and a dao interface (using aop for finder methods)
          <bean id="AppointmentService">
              <constructor-arg value="com.test.model.Appointment" />
              <constructor-arg value="com.test.service.AppointmentService" />
              <constructor-arg value="com.test.service.AppointmentServiceImpl" />
              <constructor-arg value="com.test.dao.AppointmentDAO" />
          </bean>
          
          // full blown service with custom dao implementation & some dependencies
          <bean id="OfficeService">
              <constructor-arg value="com.test.model.Office" />
              <constructor-arg value="com.test.service.OfficeService" />
              <constructor-arg value="com.test.service.OfficeServiceImpl" />
              <constructor-arg value="com.test.dao.OfficeDAO" />
              <constructor-arg value="com.test.dao.OfficeDAOImpl" />
              <constructor-arg><value>
                   <map key-type="java.lang.String" value-type="java.lang.Object">
                       <entry key="appointmentService" value-ref="appointmentService" />
                       <entry key="physicianService" value-ref="physicianService" />
                       <entry key="dateUtil" value-ref="dateUtil" />
                   </map>
              </constructor-arg>
          </bean>
          The code of the factories isn't anything too complicated. For the proxy stuff I had to understand a little bit about spring aop, nothing too major though. If you notice there is a lot of convention here, i am thinking about either generating this stuff from a properties file, better yet scanning the class path for some annotations or something like that.

          If you just want to stick to generating code, freemarker is very cool. But writing these factories has been useful at runtime also. We have done some neat stuff since I wrote them.

          Comment


          • #6
            FactoryBean can reduce the amount of repetitive configuration, as can a custom XML namespace (which wasn't mentioned yet). I must say I do not recommend the approach taken by Lloyd in general: you lose the benefit of dependency injection to some extent if you have a lot of factories that just take class names as arguments - Spring is more flexible.

            Incidentally, FactoryBean isn't a good fit for the use case in the original post - you can't add additional bean definitions in a FactoryBean - it would have to be a BeanFactoryPostProcessor.

            I nearly see the use case, and can recall similar threads (and an application I contributed to myself). The problem I have still is this: if the bean ids are paramaterised, how do you actually use them? The two use cases I saw where this made sense was where either 1) only one of the beans was used at runtime, selected by a placeholder; 2) dependency lookup was used along with a naming convention. Neither is all that common in practice, and arguably 2) is deprecated - we all know that dependency lookup is a bad idea in general, but I guess for this kind of thing it might be defensible.

            How do you propose to use the bean definitions.

            Comment


            • #7
              Surely you can always fall back to the xml approach. The factory simply provides a more terse way of writing the config (among other advantages) at the cost of not being able to deviate from the way they work. Personally I have not yet had the need to deviate at all, but if I ever do I will just configure those beans individually. Actually the factory bean could be added to or extended upon to allow better configuration.

              I originally tried a custom namespace but after about 1 hour I realized how much I hate xml. If you have written a xsd before then go for it. I plan to do some stuff this way in the future, but had I time constraints and couldn't waste days with xml crap.

              How do I use them? I am not sure we are talking about the same thing ...? here's a quick example ...

              Code:
              	<bean id="managerFactory"
              		class="com.test.ManagerFactory">
              		<property name="daoFactory" ref="daoFactory" />
              		<property name="transactionInterceptor" ref="transactionInterceptor" />
                     ......
              	</bean>
              
              
              	<bean id="daoFactory"
              		class="com.test.DAOFactory">
              		<property name="sessionFactory" ref="sessionFactory" />
                              .....
              	</bean>
              
                  <bean id="bookManager" factory-bean="managerFactory" factory-method="newManager">
                  	<constructor-arg value="com.test.model.Book" />
                  </bean>
              
                  <bean id="libraryManager" factory-bean="managerFactory" factory-method="newManager">
                  	<constructor-arg value="com.test.model.Library" />
                  	<constructor-arg><value>
                           <map key-type="java.lang.String" value-type="java.lang.Object">
                                 <entry key="bookManager" value-ref="bookManager" />
                           </map>
                      </value></constructor-arg>
                  </bean>
              
                  <bean id="editLibraryAction">
                      <property name="libraryManager" ref="libraryManager" />
                  </bean>
              Notice the map for DI into the factory created bean. This is kind of verbose and maybe one of those things a custom schema could aid.

              What originally drew me to this was for every single entity bean i had, every time I had some stupid useless lookup table, I had to write this:

              Code:
               
                  <bean id="bookManager"
                            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
                            parent="abstractBaseTransactionProxy">
                      <property name="target" ref="bookManagerTarget" />
                  </bean>
              
                  <bean id="bookManagerTarget"
                           class="com.test.manager.BookManagerImpl">
                      <property name="bookDAO" ref="bookDAO" />
                  </bean>
              
                  <bean id="bookDAO" parent="abstractDAO">
                      <property name="proxyInterfaces">
                          <value>com.test.dao.BookDAO</value>
                      </property>
                      <property name="target">
                          <bean parent="abstractDAOTarget">
                              <constructor-arg>
                                  <value>com.test.model.Book</value>
                              </constructor-arg>
                          </bean>
                      </property>
                  </bean>
              Forlookup tables that I just need basic CRUD operations on (this is very common...), I can use the injected manager factory directly. We have one app with 40 lookup tables but no config or java code needed to manage them, and a nice interface to administer the content.

              These techinques have worked quite well so I am whoring it out and hoping to get some good feedback. We made every effort to make the middle tier as lean, uniform, and easy to work with as possible. It shouldn't take 10 minutes to add an entity bean to the project.
              Last edited by lloyd.mcclendon; Jun 19th, 2007, 08:05 PM.

              Comment


              • #8
                Originally posted by Dave Syer View Post
                FactoryBean can reduce the amount of repetitive configuration, as can a custom XML namespace (which wasn't mentioned yet). I must say I do not recommend the approach taken by Lloyd in general: you lose the benefit of dependency injection to some extent if you have a lot of factories that just take class names as arguments - Spring is more flexible.

                Incidentally, FactoryBean isn't a good fit for the use case in the original post - you can't add additional bean definitions in a FactoryBean - it would have to be a BeanFactoryPostProcessor.

                I nearly see the use case, and can recall similar threads (and an application I contributed to myself). The problem I have still is this: if the bean ids are paramaterised, how do you actually use them? The two use cases I saw where this made sense was where either 1) only one of the beans was used at runtime, selected by a placeholder; 2) dependency lookup was used along with a naming convention. Neither is all that common in practice, and arguably 2) is deprecated - we all know that dependency lookup is a bad idea in general, but I guess for this kind of thing it might be defensible.

                How do you propose to use the bean definitions.
                We use them by name on our client. The parameterization is only used as part of the definition. Once the bean is defined, you use them by name as usual. We want to use the interfaces by name on the client, so we end up with a class that we use to get an instance from Spring

                Code:
                FooService fooService = Configuration.getFooService();
                // ...
                public static FooService getFooService() {
                    return (FooService) appContext.getBean("fooService");
                }
                Namespaces were the best way to go here ... based on Appendix B in the reference manual, and the note which said you could do whatever you wanted to with the bean definitions, I put together some custom tags for our configuration.

                The bean definitions are generated by, for example,

                Code:
                <myapp:remote-service-bean serviceUrlRoot="rmi://${middle.tier.server}:9000"
                        serviceClass="org.springframework.remoting.rmi.RmiProxyFactoryBean" beansNeeded="
                        com.foo.service.FooService
                        com.foo.service.BarService
                        com.foo.service.SnarkService
                        com.foo.service.FlapService
                        com.foo.service.SnarktasticService
                        com.foo.service.EnoughService
                        com.foo.service.OneMoreService
                        com.foo.service.WillItEverEndService
                    "/>
                Getting the template of the bean definition out of the Spring configuration file also removed the need for special handling of the PropertyPlaceholderConfigurer, which I had not got around to bringing up.

                Using the custom namespace also makes it easier to (someday) switch to annotations for indicating what class is provided as a bean.

                Comment

                Working...
                X