Results 1 to 7 of 7

Thread: Where to do wiring

  1. #1
    Join Date
    Jan 2009
    Posts
    2

    Default Where to do wiring

    Hi,

    I'm starting to evaluate Spring and need some pointers.

    We usually build our enterprise applications in Eclipse and most often we have the same structure. That is, three different projects in our workspace:
    1. Dynamic Web Project (for the WAR)
    2. Java Project (JAR for our service layer, that is referenced from the web project)
    3. EAR Project for packaging the above.

    Now, adding spring to this application would mean we have to decide where to do the wiring, in which project, or in other words: Where to put applicationContext.xml.

    My guess would be to do the wiring in the Web Project, since it can "see" the classes in the Java Project.

    Is this the right way?

    Best regards,
    Ai

  2. #2
    Join Date
    Mar 2005
    Location
    Paris
    Posts
    54

    Default

    I would do this kind of separation for the eclipse projects materializing the design layers. You can add more projects if you want (external service, etc).

    Theses are the bases:

    1- Web: The web project (containing java classes for view/manage beans)
    2- Business: The Business Layer
    3- Persistence: Persistence layer

    Each layers/project would have its own spring-xxx-xxx.xml wirering files contains in a src/config source folder. For testing purpose, you should add a test/config source folder with the needed mock object spring configuration... You should be able to test in isolation each layer: persistence, business+persistence, web+business+persistence.

    In the Web project, I would add a spring-web-xxx.xml file wirering web components.

    I would add the main "applicationContext.xml" file (you can rename it) inside the web-inf folder (or elsewhere).

    The applicationContext.xml file will have to import all wirering file: spring-web-xxx.xml, spring-business-xxx.xml, spring-persistence-xxx.xml.

    In the spring documentation, you will find the necessary Spring listener to be put in your web.xml (or face-context.xml, or else) to load the applicationContext.xml.

    Try to be "all spring oriented", meaning let spring manages all components (manage/action bean, business components, persistence layer beans).

  3. #3
    Join Date
    Nov 2006
    Location
    Boston, MA
    Posts
    303

    Default

    Organize your modules by functionality, not by the type of classes. Generally, you are on the right track.

    Your "business layer" may be represented by a set of independent functional-domain-specific modules that live outside your web application. They should not contain any Spring wiring (except, perhaps, in the Tests tree.) The idea is that you have re-usable independent modules that can be wired into any application and configured differently with different implementations of its dependencies, etc. I resent the notion of a separate project for Persistence. Persistence is an implementation detail of a business component. See my arguments here:

    http://forum.springframework.org/showthread.php?t=64147

    So, each your business component should define the domain model and service APIs for the functional domain it represents (e.g. User, Product, Account, etc.) I would package your DAOs under your component-specific service package. (DAOs may need to be application/data source specific, so the component may also expose the DAO interface so that the applications may provide their own implementations.) You will generally have one DAO per business component. Not a DAO per domain entity object, like so many projects have, unfortunately! You will also have as "common" component that will contain domain objects and interfaces that may be used by multiple business components.

    You wire everything on the application level. because that's where you actually decide which implementations of your [generic, reusable] services and daos are being used for this particular application. Nevertheless, don't pile everything into a single configuration file. Also, do not use grouping by type (e.g. service-config.xml, daos-config.xml, etc.) Instead, again, group your configuration by the functionality. For example:

    common-context.xml
    user-app-context.xml
    product-context.xml
    error-resolving-context.xml
    etc.

    If you package your service configuration with your business components, you hard-wire the particular configuration into the component itself. (Although in some cases you might want to do that, it is rarely what you really need.) Doing the wiring at the application level makes your configuration app-specific, which is what it needs to be most of the time.

    HTH,
    Constantine

  4. #4
    Join Date
    Mar 2005
    Location
    Paris
    Posts
    54

    Default

    Hi Constantine,

    you post is very interesting. I understand your point and would like to agree with it.

    I agree totally with the configuration isolation of "common and transversal components" as:

    Common lib
    • common-context.xml


    Implementation specific, transversal components:
    • error-resolving-context.xml

    I would add
    • gigaspace-cache-impl.xml

    • transaction-jta.xml

    • jndi-connection.xml


    Integration to other modules
    • mailing-api-context.xml

    • remote-connector-api.xml


    For the case of Product and User (service & Dao) declared in 2 separate configuration files, I see a issue about separating theses 2 contexts if they are part of the same Domain Model (or they will be part in future evolution):

    user 1 <-- n products

    While I do understand that you may see some benefits to include both Product-service and Product-Dao inside the same file, I would not separate the Product-Dao and the User-Dao if they are dependent each other at the Entity level. I mean if you cannot load into the context Product-context.xml without User-context.xml, there's no benefit to separate them.

    But the case is also true to me if 2 different applications are using the same database schema for different use cases, I would not separate the persistence of each application if they are using the same domain model.

    For example if we have a User-administration application and a Product-store application.

    In this case, I would have a

    • business-user-administration.xml : business classes for the user-admin application

    • product-store.xml : business classes for the product store application


    while having a single file persistence (of big grouping of entities) knowing User-administration and Product-store are using all domain model objects in the persistence.

    The issue I have (and it is not a minor one) is that any small application wanting to use a little part of the persistence layer (report-sells-of-the-day) will have to load in memory most (or all) the domain model. But this is more a "hibernate" issue, because the persistence entities are dependent at this level only.
    Last edited by etienno; Feb 11th, 2009 at 08:09 AM.

  5. #5
    Join Date
    Nov 2006
    Location
    Boston, MA
    Posts
    303

    Default

    Quote Originally Posted by etienno View Post
    Hi Constantine,


    For the case of Product and User (service & Dao) declared in 2 separate configuration files, I see a issue about separating theses 2 contexts if they are part of the same Domain Model (or they will be part in future evolution):

    user 1 <-- n products

    While I do understand that you may see some benefits to include both Product-service and Product-Dao inside the same file, I would not separate the Product-Dao and the User-Dao if they are dependent each other at the Entity level. I mean if you cannot load into the context Product-context.xml without User-context.xml, there's no benefit to separate them.

    But the case is also true to me if 2 different applications are using the same database schema for different use cases, I would not separate the persistence of each application if they are using the same domain model.

    For example if we have a User-administration application and a Product-store application.

    In this case, I would have a

    • business-user-administration.xml : business classes for the user-admin application

    • product-store.xml : business classes for the product store application


    while having a single file persistence (of big grouping of entities) knowing User-administration and Product-store are using all domain model objects in the persistence.

    The issue I have (and it is not a minor one) is that any small application wanting to use a little part of the persistence layer (report-sells-of-the-day) will have to load in memory most (or all) the domain model. But this is more a "hibernate" issue, because the persistence entities are dependent at this level only.
    Wow-wow... Wait a minute! I don't think you read my post carefully. Sounds like you and I are totally NOT on the same page. Not even close! Also, if you read some of my other posts on the general architecture and packaging issues in this forum, you should be able to clerarly see our differences.

    No DAO should have dependencies on other DAOs. Services depend on other services. Moreover, you should not have a logical Persistence layer as a single module in your application! I keep saying this again and again: it is wrong to organize projects by type (domain vs. business logic vs. persistence, etc.) Most people do that, and they are WRONG! Because it couples everything with everything! Why it is not obvious to so many people is beyond me. This is exactly the issue you are facing! You have a large "persistence" module, and you always need ALL of it regardless of how thin the slice of its overall functional spectrum the given application needs.

    The easiest and most natural way to organize things is by functionality. This way, each application loads only those functional components (including the domain model, service and DAO for each) that it needs, and nothing else.

    Persistence of a particular functional domain is the implementation detail of that functional domain's use cases. Therefore, persistence must be abstracted (as a separate module - dao) under the related services. All you need to define in your Products configuration file is, for example, the "productService" bean and its dependencies such as the "productsDao." Now, your "productsDao", just like the DAO beans for other services, will have a dependency on your "dataSource" bean that should be defined in some kind of common configuration XML file. If your Product service API methods take User domain entities as arguments, none of that will be reflected in your Spring configuration. You don't inject such objects, they are passed to the methods as arguments. If your product service under the hood calls a method on the User service, than the reference to the "userService" bean - defined in its separate configuration file - may be injected as a property in the definition of your "productService". Any Spring bean defined in any configuration file - within the same application context - is accessible to the definitions in other files. For example, your product context file may look like this:

    Code:
        <!-- Products Service definition; depends on products DAO defined locally and User service bean defined in "user-context.xml"  -->
        <bean id="productService" class="com.mycompany.product.service.ProductService">
            <property name="dao" ref="productsDao"/>
            <property name="userSvc" ref="userService" />
        </bean>
    
        <!-- Products DAO definition  -->
        <bean id="productsDao" class="com.mycompany.products.service.dao.ProductsDao" >
            <!-- set data source property by injecting DS bean defined elswhere in the app context as 'dataSource', e.g. in "common-config.xml"   -->
            <property name="dataSource" ref="dataSource"/>
        </bean>
    If your Product service does not have any other dependencies, this may be all you need in such configuration file. If your Product Component has other Spring-managed classes, e.g. some ProductsConfig module, some helper classes, validators, etc., you will add them here as well. But, do not put anything here that is NOT specifically Products-related! Separate concerns - for your own sake and the sake of others who will be working with this stuff. Even if your Products component does not function without the dependency on the User. But what if tomorrow you introduce another functional domain that Products will depend on. According to your reasoning, you would need to add that into the same configuration file. What is even more realistic is that there will be other functional domains/services that call the Products Service. Do you put all of those bean definitions in the same file? Why? Who said it's a good idea. Placing definitions into separate files does not make them invisible to other definitions in the application context. Group the bean definitions by functionality and inject any dependencies using the bean IDs defined in external files. that's it! very simple.

    You should NOT be reusing the "Persistence layer." You should be re-using the functional domains! Moreover, if you take the hard-wired configuration out of the domain-specific JARs (e.g. products.jar), you will make your functional components flexible by allowing each application to configure them whichever way it needs. Two different applications may use the same products.jar but provide different implementations of the DAOs if they talk to different data sources - for example. If several applications use the same data source, then, by all means, use the same datasource configuration for all of them. But package your configuration files with the applications! It is a cheap price to pay for flexibility. It will allow you to deploy those applications anywhere you want. If you have several web applications that will run on the same server and use the same Products component, that's great. Deploy your products.JAR in the common area on the server instead of putting it inside each WAR file. One may argue that in such cases it may make sense to place the Products configuration (wiring of all the dependencies) within the same jar so that the applications don't have to duplicate that configuration. The downside is that the JAR becomes hard-wired for a particular DAO/datasource configuration, etc. Instead, I prefer to allow each application to have the last word on what configuration it needs. And the service jar becomes more reusable and deployable in different environments with different applications, since the applications themselves take responsibility of the final configurations. However, depending on the intended usage of the service or/and application, it may be the right solution - to hard-wire such configuration within the service jar once and for all.

    Hope this helps at least a little bit. But if, at least for now, you are set in your ways and keep thinking organization by type (e.g. "persistence layer") vs. organization by function, you and I will be speaking different languages. But if organization by functionality starts making sense to you, the rest should become just obvious. And you will be amazed how simple life gets...

    Good luck,
    C

  6. #6
    Join Date
    Mar 2005
    Location
    Paris
    Posts
    54

    Default

    Hi Constantine, thanks for your answer. And I am following you 100%. I know there's probably an issue to let Services load any DAOs, and not only Services. I agree that separating functional component is a nice way. That's why I am trying to understand your point.

    Quote Originally Posted by constv View Post
    No DAO should have dependencies on other DAOs.
    Of course. I Agree 100%.

    Quote Originally Posted by constv View Post
    Services depend on other services.
    So I guess you would not agree with this design and package naming:

    Code:
       <!-- let say it is a JSF Example -->
        <bean id="homePageViewBean" class="com.mycompany.view.homepage.HomePageViewBean">
            <property name="productService" ref="productService" />
        </bean>
    
    <!-- Product Business service bean, usually put the Transaction here -->
        <bean id="productService" class="com.mycompany.business.product.ProductService">
            <property name="productDao" ref="productDao"/>
            <property name="userDao" ref="userDao" /> <!-- this is where you disagree? true? -->
        </bean>
    
        <!-- Product DAO definition  -->
        <bean id="productDao" class="com.mycompany.persistence.product.dao.ProductDao"/>
         <property name="dataSource" ref="dataSource"/>
        </bean>
    
    
        <!-- User DAO definition  -->
        <bean id="userDao" class="com.mycompany.persistence.user.dao.UserDao"/>
         <property name="dataSource" ref="dataSource"/>
        </bean>
    If you say that Dao X are implementation of Service X, you can inject Service X instead of Dao X. That's ok with me. Like in my example below, I do usually allowed "Service" to be injected with all DAO they need, but causing the functionality isolation to be broken.


    Code:
        <bean id="productService" class="com.mycompany.business.product.ProductService">
            <property name="productDao" ref="productDao"/>
            <property name="userService" ref="userService" /> 
        </bean>
    Quote Originally Posted by constv View Post
    The easiest and most natural way to organize things is by functionality. This way, each application loads only those functional components (including the domain model, service and DAO for each) that it needs, and nothing else.
    Ok, lets do that.

    Question:
    Where do you put your Transaction Handling? I doubt you can put it inside your Service, because Services are use by other Services. Same thing for DAO: no transaction handling, no exception handling in the DAO.

    You then need another level to manage the Transaction, at the level of a "Service aggregation", or "Service Transactional" closely link to its usage? This add another level.

    I am saying that because if you let Service talk to any Daos to accomplish their job, the Service can be Transactional (but not aggregated), and the Dao are not transactional and aggregated.

    What is your rule of thumb for Transaction (and Exception Handling) in your design?

    BTW, I am not saying that you are wrong, but your design differ from the examples in the Spring documentation. To manage a Single Transaction, the spring documentation propose to make a single Transaction in the ProductService around the ProductDao and the InventoryDao (injected in the Product Service) : 12.2.8. Transaction management strategies: http://static.springframework.org/sp...rence/orm.html. I know it's a "hello world" example, but that's probably the reason why most people are using the dao layer as an whole.
    Last edited by etienno; Feb 12th, 2009 at 07:06 AM.

  7. #7
    Join Date
    Nov 2006
    Location
    Boston, MA
    Posts
    303

    Default

    Now we are getting close... I am glad you are seeing my point. One note... I would recommend keeping your business component configurations (Products, User, etc.) apart from the front-end web application stuff such as controllers, etc. The web application specific stuff should sit in a separate file and reference the bean dependencies from the business modules. In other words, your configuration groupings should be similar to your project structure: one module per each functional domain, and one module per each client application (e.g. web application.) In other words, the following configuration code

    Code:
    <!-- let say it is a JSF Example -->
        <bean id="homePageViewBean" class="com.mycompany.view.homepage.HomePageViewBean">
            <property name="productService" ref="productService" />
        </bean>
    should live in the web-app-related configuration xmls with other page view beans. That's how I'd do it. Of course, you may end up having more than one web-app spring config xml, if you have lots of front-end beans to configure. If so, create a separate subfolder in your configuration directory - for the web application config files, specifically.


    Question:
    Where do you put your Transaction Handling? I doubt you can put it inside your Service, because Services are use by other Services. Same thing for DAO: no transaction handling, no exception handling in the DAO.
    That's incorrect. That's exactly where you should put it. Your service APIs should be transactional. You can do this using Spring annotations, or declaratively using an aspect, in you Spring configuration file. It may be more robust to tie your transactionality to the code of the service implementation using annotations on the public method level. Your transactions may be configured in different ways. See the reference guide. The Spring default setting will ensure that the failure of a nested transaction will cause the outer transaction to roll back. So, it is absolutely safe to nest service calls while each such service method is transactional. If you require a different behavior, adjust the transaction properties accordingly.


    BTW, I am not saying that you are wrong, but your design differ from the examples in the Spring documentation. To manage a Single Transaction, the spring documentation propose to make a single Transaction in the ProductService around the ProductDao and the InventoryDao (injected in the Product Service) : 12.2.8. Transaction management strategies: http://static.springframework.org/sp...rence/orm.html. I know it's a "hello world" example, but that's probably the reason why most people are using the dao layer as an whole.
    That's exactly what I have just said, and it goes along with everything I have said earlier. Regarding two DAOs used by the same service in the example... this is ok if there is no separate "Inventory" service, and both DAOs are only used by the Product service. That's how I would do it.

    About exceptions.... I have written volumes in this forum about exception handling. The stuff is scattered all over. I have provided some links here:

    http://forum.springframework.org/sho....php?t=67379#3
    Last edited by constv; Feb 13th, 2009 at 03:04 PM.

Posting Permissions

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