Announcement Announcement Module
Collapse
No announcement yet.
Layer and Vertical Architecture in Spring Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Layer and Vertical Architecture in Spring

    Hello All,
    We have multiple applications and libraries. These are developed by multiple teams across the organization. To avoid confusion and to have complete control over dependency we would like to enforce proper vertical slice and layering in the application with the help of Spring.

    Our initial sketch looks as follows:
    app-UI ---> app2-UI
    |
    |
    V
    app-logic ----> app2-logic
    |
    |
    V
    integration ----> app2-integration

    In app1 we are doing some thing as below:

    app-UI:Spring-MVC (war) has spring-mvc-servlet.xml & applicaionContext.xml.

    mvc-servlet.xml contains Controller and other web related declaration and etc..
    applicationContext.xml has beans declaration specific to web app and reference to logic layer as follows:
    Code:
    <bean id="commons-lib" class="org.springframework.context.support.ClassPathXmlApplicationContext">
    		<constructor-arg value="classpath*:/cBeanRefContext.xml" />
    	</bean>
    logic layer: (packaged as jar) and all beans are declared in cBeanRefContext.xml. This is shared by UI layer and different vertical Apps.
    This xml will have all common beans and reference to integration layer as follows:

    Code:
    <!-- load Integration related context file -->
    <bean id="commons-lib" class="org.springframework.context.support.ClassPathXmlApplicationContext">
                    <constructor-arg>
                        <list>
                               <value>env.xml</value>
                         <list>
                    </constructor-arg>
    		<constructor-arg value="classpath*:/iBeanRefContext.xml" />
    	</bean>
    
    <!-- business logic bean declaration goes here -->
    <bean id="loggerInjector" class="com.opsh.common.logging.LoggerInjector" />
    <bean id="auditClazz" class="com.opsh.common.auditing.AuditingProxy"/>
    <bean id="securityClazz" class="com.opsh.common.security.SecurityProxy"/>

    Int-App: packaged as jar and all integration related beans are declared in iBeanRefContext.xml. This contains MDB's web services related to integration to external app and etc.,

    This is how we would like to strictly enforce and control the layering and slicing.

    The problem we are facing is, when we try to use loggingInjector or any beans from the logic layer in the UI layer, we are getting NullPointerException. However, in the server log we can see that cBeanRefContext.xml is getting loaded and the output is as follows:

    Code:
     <Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@fd4662: defining beans [loggerInjector,auditClazz,securityClazz]; root of factory hierarchy>
    My questions are:
    1. Is this the right way of doing?
    2. Is this possible at all?.
    3. Where is that I am failing or am I doing something wrong here to get Null pointer exception?
    4. What is the correct way of loading context files in the spring-mvc.?
    Please Help!.

    I've just noticed that if I use <import resource="classpath*:/cBeanRefContext.xml"/> in mvc-servlet.xml I don't get any Nullpointer expection and everything works fine. But I think this may not be the right way of doing it? Is that right?

    John
    Last edited by srcfrguser; Nov 16th, 2008, 05:55 PM. Reason: correction made about mvc-servlet.xml and added new findings about <import/> tag

  • #2
    Hi. Thank you for raising your questions around software architecture.

    One advice I can certainly give you is you don't allow your business rules or entities to be accessible from the UI layer. Always define Data Transfer Objects as a means of transferring data between the UI layer and the Business layer. I've seen examples that expose entities to the UI layer. But it is a better design to use DTOs, offering flexibility, security and better decoupling features.

    Consider the following:

    application (ui, integration) -> service -> domain -> gateway

    Further information can be found here. But I'll provide an overview.
    The Application layer contains user interface implementations (JSP, controllers, AJAX, etc.). The common pattern to adopt here is the Model-View-Controller pattern.

    The Service layer acts as a Facade between the Application and Domain layer. This means that any changes to the Application layer won't affect the Domain layer and vice versa (along with the use of DTOs). It can also handle transactions, exceptions and logging. The Facade pattern is adopted here.

    The Domain layer is where the business rules are kept. Objects normally kept here are entities and data transfer objects (DTOs). Work with DTOs to, say, transfer form field data from a web page to the Domain layer ready for processing. The Strategy and Factory patterns are used here, where the Factory pattern is used to instantiate entities to work with.

    The Gateway layer is your interface between the application and the external resource (i.e. database, SMTP, MQ, FTP, etc.). Work with entities to retrieve or persist data. DTOs can also be used here acting as MDBs. perhaps you can call these DTOs as MDBs if you like. The Gateway pattern or DAO pattern is used here.
    Notice that I've also mentioned "integration" as part of the application layer. This is a (sub)layer used if you want external applications to talk to you rather than you talking to them. This Application Integration layer could be implemented as a web service, for example. You can take a look at an example here (http://forum.springframework.org/sho...75&postcount=4).

    The principle behind the above has been adopted from http://martinfowler.com/eaaCatalog/serviceLayer.html (thanks Martin!).

    Let us know what you think. We can try and help you with a good layered design.

    Comment


    • #3
      For the project i work at the moment i did the following architecture. It's project where we build like 10-15 portlet applications and all of them are using the same architecture.

      One of the main constraints was the possibilitiy to allow vertical deployments, which means that each portlet application bundled with the framework must be deployable on its own. Which again means, that we dont want to have a services layer with all the services in one project etc.

      What i did was the following structure:

      Web
      We have mainly Faces portlets where we use the IBM Widget Library for better IDE integration and tools (Rational Application Developer).


      Service Layer
      All our use case specific rules are in here. This is where we actually do our business. The access to this layer is done over a Business Delegator. As we use spring, we wanted to have a typed access to the service beans from the Page Code of JSF. The lookup goes like:

      BeanUtil.getMyServiceBDFactory().createMyServiceB( );

      The BeanUtil encapsulates the logic to see if the lookup to the service is done on servlet level/JSF level or portlet level.

      DAO Layer
      This layer is for our CRUD operations and quiet straight forward. We use iBatis as our ORM choice.

      The DAO classes provide DTO's to the service layer and the service layer either gives those DTO's to the Web Layer, when the UI is data centric or a bean that holds the UI-specific data, if there's the need for it.


      Each Project has a Web(Portlet)-Project, a Services Project (Service,DAO,Bean and Util classes which are use case specific) and a FrameworkServices project (all common services,dao,util classes)

      Comment


      • #4
        Thanks for your reply. I understand the layers in general architecture and we try to strictly follow layering.
        Things that we are struggling with is, using Spring in layer and vertical architecture.

        How do we share ApplicationContext in layering architecture?
        How do we initialise and share the application context across vertical architecture?

        We are struggling in understanding the Spring classloader hierarchy .

        Have you tried this kind before? If so can you share your applicationContext.xml in web layer, middle layer and in the integration layer PLEASE?

        Comment


        • #5
          The way I look at it, if the middle layer and integration layer are separate projects resulting in as individual jar files, and the web layer depends on those two jars then you have the application context within the web layer.

          Remember, though it helps to have separate projects for each layer, it is not necessary. You can simply have one project and use packages to separate the layers within. For example:



          But of course, if you like you can separate the layers into different layers:

          Comment


          • #6
            Hey,
            Thanks for interest on and patients on this. We are using eclipse and idea editors in development. Our projects structure in eclipse looks similar to the one that you shown in the singleProject view.
            Now we are getting closer to my original question
            Based on the project structure I presume you have applicationContext for each layer for example appContext_gateway.xml, appContext_domain.xml, appContext_service.xml, and appContext_ui.xml.
            To maintain this layering during runtime and deployment, I am assuming UI layer will be loading Spring beans only from the service layer which in turn will have reference to domain layer and this in turn will have reference to gateway layer.
            So, UI application context will have no clue about either domain / gateway layer.

            My question is, how do you load this in the Spring classloader? I am more interested in looking inside appContext.xml. Are you just using <import resource.../> tags in each appContext-xx.xml or some other way?

            Am I helping you to understand my question ? or you are still confused and not clear?

            Thanks John

            Comment


            • #7
              Take a look at my post in another thread. It touches on the issue you are discussing. I think you guys are getting it wrong since with such packaging your architecture is totally application-centric, not service-oriented. It is a very common mistake, so you are not the only ones.

              http://forum.springframework.org/sho...074#post214074

              Comment


              • #8
                as i stated in my last line:

                "Each Project has a Web(Portlet)-Project, a Services Project (Service,DAO,Bean and Util classes which are use case specific) and a FrameworkServices project (all common services,dao,util classes)"

                As you can see services,dao's, beans,utils for a specific use case is bundled in one utility project and can be reused by any kind of plattform, be it a Web Service, be it a batch programm etc.

                The wiring of all this services,dao's etc. is done on the "front end" application, as only the "front end" application knows what it needs.

                If you want to do a non-application-centric package, you can use the same structure without problems as it encapsulates all the services/dao's/Beans/utilities etc. needed for that

                Comment


                • #9
                  Originally posted by uenluena View Post
                  as i stated in my last line:

                  "Each Project has a Web(Portlet)-Project, a Services Project (Service,DAO,Bean and Util classes which are use case specific) and a FrameworkServices project (all common services,dao,util classes)"

                  As you can see services,dao's, beans,utils for a specific use case is bundled in one utility project and can be reused by any kind of plattform, be it a Web Service, be it a batch programm etc.

                  The wiring of all this services,dao's etc. is done on the "front end" application, as only the "front end" application knows what it needs.

                  If you want to do a non-application-centric package, you can use the same structure without problems as it encapsulates all the services/dao's/Beans/utilities etc. needed for that
                  uenluena,
                  what you are describing sounds good. I was responding to the other posts (shahnawazshahin and srcfrguser.) Specifically, the illustration with the package structure.

                  Comment


                  • #10
                    Thanks for your feedback constv.

                    I've had a look at the other thread. I've actually seen a similar package structure to the example that you've provided from the post link (http://forum.springframework.org/sho...074#post214074). This is something I'll definitely keep in mind and update. Perhaps I've oversimplified my examples a bit.

                    Having a look at the post through, I notice that the pattern showing that if there are n number of Domain objects, then there should be n number of service implementations. I thought a service implementation is course grained by design/nature. For example:
                    org.myapp.xxx.domain.ordermanagement
                    Order
                    LineItem
                    Product
                    Supplier

                    (business rules are kept here and had data access implementations also using Template method, or link to DAOs using Strategy).

                    (optional manager classes can be used like OrderManager, but would lead to an anaemic design).
                    org.myapp.xxx.service
                    OrderManagementService <- defining methods like add lineItem, cancelOrder, etc.
                    org.myapp.xxx.service.impl
                    StandardOrderManagementService <- interacts with the domain objects in a work flow manner
                    Is this no longer the case?

                    (Btw, what does svcone and svctwo mean?)

                    Comment


                    • #11
                      Hi shahnawazshahin,

                      By "svcone" and "svctwo" I meant "some service One" and "some svc Two"... Sorry for the incoherent names.

                      Regarding the Domain/Service relationships... I don't see the n-to-n cardinality between the domain objects and service implementations... What makes you think that?

                      Let's say you have a certain area of functionality that you want to be implemented as a piece of software. In your example, it is "Managing Orders." Great. So, we will call the software that does this for us "Order Management Service", for example. The first thing we need - obviously - is to figure out what real-world concepts/entities are managed by this Service. So we come up with a list of "things", entities, like:

                      Order
                      LineItem
                      Product
                      Supplier
                      etc.

                      Note that these are just pure order domain entities that have nothing to do with any business rules. They have certain properties, associations with each other, and, perhaps, some very basic functionality without which some of these concepts won't make sense. This ensures that these domain objects may be reused by any implementation of the order service. They define the Domain Model, the objects that live in our "world of order management." The second thing we need to define is the use cases for the order service. (In reality, of course, we would go through a few iterations adjusting the Domain Model based on the Use Cases, and vice versa.) Ultimately, the use cases will define the Service API. Ok, now, we have what fully defines our service: the Domain Model and the API. Note, I have not mentioned the implementation. What we have so far, is completely reusable and may be used for various implementations of the service. The API provides the access to the business logic that lives within the implementations of the service. (I repeat, it is the service classes that implement business logic, not the domain objects.) If, at the very least, the service JAR contains the Domain objects and service interfaces only, anyone can still use it to implement their own versions of the service. In most cases, however, you would also provide an implementation of the service together with the Domain and API in the same jar. Applications may re-use it as is, or, if they absolutely have to, they can use the domain model and API to provide their own implementation, or extend the existing standard implementation. Any other service or application that has a dependency on "Order Management" will have to include the Order jar as its dependency and that's it. If your application (or other service) deals with orders, it will automatically be exposed to all of your Order Domain classes and service API. It should do any order processing via the Order service. Your services should live outside the applications and "parallel" to other services. In other words, applications and other services simply treat them as lib dependencies.

                      This is a very simple and elegant approach. When several applications need to use the same service, you have several simple choices:

                      1) If all your applications run on the same server, package them as "thin" wars (if they are web apps) that do not include the reusable jars; instead, deploy all common libraries - such as Spring, Jakarta Commons, Log4J, and your generic services - in the common area on the server where they will be accessible by all applications that use them;

                      2) If your applications run on different boxes but use the same libraries (Spring, log4J, and some of your generic services), its ok to deploy the jars on each server. That's what you do with libraries like Spring. It should not be any different with your reusable services. The only caveat is that you should make sure they are architected and packaged to be reusable.

                      3) If you don't want to distribute your service and want to host it, while applications all over the world would access it remotely, then make it available, for example, through a web service; in that case your WS is the client application of your service, and it would use the local jar with your service as one of its dependencies. (For God's sake, people, don't use web services, or any kind of remoting when all your "services" and apps run on the same box! I am not joking, I have seen this way to many times. I have no idea what kind of drug makes those people do that... Perhaps, they had heard somewehere that web services were "in"?)

                      Very simple. Again, because your service package provides its open API, clients can still use it to build their own implementations and reuse the domain model.

                      My ultimate advice is: never think of your services as part of your client application, however tempting it may be. That would be a very shortsighted view that will backfire as soon as you realize that you have other needs for the same functionality (e.g. nightly batch process, another web application that does a similar thing, etc.) Always package them as independent modules and deploy as dependencies/libraries. Life becomes easy!
                      Last edited by constv; Nov 21st, 2008, 01:09 PM.

                      Comment


                      • #12
                        Hi constv. Thanks for the valuable feedback. In any given order, here is my feedback:

                        Regarding the Domain/Service relationships... I don't see the n-to-n cardinality between the domain objects and service implementations... What makes you think that?
                        I must have misinterpreted your example in your post (http://forum.springframework.org/sho...074#post214074). My apologies for that - at least this is now clarified.

                        1) If all your applications run on the same server, package them as "thin" wars (if they are web apps) that do not include the reusable jars; instead, deploy all common libraries - such as Spring, Jakarta Commons, Log4J, and your generic services - in the common area on the server where they will be accessible by all applications that use them;
                        With this design, I agree. I think this does work very well.

                        2) If your applications run on different boxes but use the same libraries (Spring, log4J, and some of your generic services), its ok to deploy the jars on each server. That's what you do with libraries like Spring. It should not be any different with your reusable services. The only caveat is that you should make sure they are architected and packaged to be reusable.
                        Agree if each server is completely isolated. Off the topic - could the commons libraries be available off a shared environment (like a file share if each server has access to, where possible)?

                        3) If you don't want to distribute your service and want to host it, while applications all over the world would access it remotely, then make it available, for example, through a web service; in that case your WS is the client application of your service, and it would use the local jar with your service as one of its dependencies. (For God's sake, people, don't use web services, or any kind of remoting when all your "services" and apps run on the same box! I am not joking, I have seen this way to many times. I have no idea what kind of drug makes those people do that... Perhaps, they had heard somewehere that web services were "in"?)
                        I agree with this statement with most cases. If the application can make do without remoting then don't complicate the issue. However, I see why people would do this to "future proof" their application and make it easier to migrate to multi-application based or even multi-tiered architecture.

                        Having the right design using a layered architecture makes the application extensible. The 'Facade features' of the Service layer makes it possible to have mutiple application layer types (i.e. one for the user interface, and the other as an integration like web service). I guess the example having a shared common library makes it possible to 'extend' the features of the solution, allowing to introduce another application library (to provide a web service, for example) in future.

                        However, with regards to multi-tier applications you have one server that purely handles business logic and another server that handles the application or presentation layer. This is valid if one wants to distribute responsilibities to different servers (i.e. one handles the bus rules, and the other handles page requests, sessions, etc.). In this case, perhaps remoting would be used as one way to achieve this.

                        What we have so far, is completely reusable and may be used for various implementations of the service. The API provides the access to the business logic that lives within the implementations of the service. (I repeat, it is the service classes that implement business logic, not the domain objects.)
                        I'll have to disagree with this one I'm affraid. Although it is commonly found that business rules are found in the service layer, it is generally a bad practice. Having the business rules within the Service layer calls for an anaemic design, and there are a lot of discussions around anaemic model vs rich domain model.

                        Having the Service layer directly accessing the Data Access layer is also incorrect, yet there are many examples out there that does this. The correct approach is to have a Factory class that instantiates Domain objects where any DAO dependencies can be injected into those objects. The other option that Spring provides is to use AOP and the @Configurable annotation feature.

                        My understanding is that the Service layer would know what to do when the application calls for a specific operation that needs to be done, but doesn't know how each specific task is done to complete the operation. Instead those individual tasks are delegated to the Domain objects.

                        So in effect, the Service layer acts as a 'workflow' rather than defining the business rules. Thus the business rules should be defined in the Domain layer. The word 'Domain' stands for just that, 'Business'.


                        Shah.

                        Comment


                        • #13
                          Shah,

                          you make all very good points. I think you may have somewhat misunderstood me on a few things though...

                          I'll have to disagree with this one I'm affraid. Although it is commonly found that business rules are found in the service layer, it is generally a bad practice. Having the business rules within the Service layer calls for an anaemic design, and there are a lot of discussions around anaemic model vs rich domain model.

                          Having the Service layer directly accessing the Data Access layer is also incorrect, yet there are many examples out there that does this. The correct approach is to have a Factory class that instantiates Domain objects where any DAO dependencies can be injected into those objects. The other option that Spring provides is to use AOP and the @Configurable annotation feature.

                          My understanding is that the Service layer would know what to do when the application calls for a specific operation that needs to be done, but doesn't know how each specific task is done to complete the operation. Instead those individual tasks are delegated to the Domain objects.

                          So in effect, the Service layer acts as a 'workflow' rather than defining the business rules. Thus the business rules should be defined in the Domain layer. The word 'Domain' stands for just that, 'Business'.
                          1) Some business rules are very much application-specific, and they belong in the front-end tier (not UI, but on the level of the Controller.) Generic business rules are packaged within the services whose only purpose is to encapsulate re-usable business logic. So, yes, we disagree..

                          2) DAOs must always be extracted into a separate tier from the services and injected. Where did I stated the opposite. The service has no business of knowing how the data tier is implemented, and what data source is being used. Services should be configurable. The ultimate client must not be exposed to the data tier implementation details. But whoever hosts the service should be able to provide the correct DAO implementation and inject it into the service at run-time. It just often happens so that clients and services are running on the same box and are deployed by the same people in the context of the same application. So people often view the DAOs as application-specific components. In reality, DAOs are data-source-specific configuration of a service.

                          3) Basically, if you read carefully what I have stated before, you will realize that we are talking almost about similar things regarding the domain model. But with certain differences. I promote bundling the domain-specific entities together with the API that reflect the use cases that manage these domain concepts. I do see a difference between the "nouns" and the "verbs". So, I conceptually disagree that all such entities should have functionality hard-coded in them. Especially because the functionality may vary from context to context. That is why there may be different implementations of the same functionality (API), but all implementations may conform to the same public interfaces. The clients that use the service are not aware of the implementation details of the service but are exposed to the domain entities and the service's public methods. So, the domain model is part of the public interface. I have also stated that domain entities must possess as much functionality as they can - but it absolutely must be the kind of unambiguous functionality that may not be questioned or modified. Like zip code validation within the ZipCode entity, etc. However such entities should know nothing about any strategy or mechanism that may be used to persist them, any type of logic that may be applied to manage them in various contexts, etc. You can have a concept of an Account, but different institutions may handle accounts completely differently. They may all have a save, create, register, etc. use cases with completely different requirements. They should be able to reuse the same domain model, and provide their own implementations of the same account API instead of re-inventing the whole Account domain model from scratch.

                          Generally, my philosophy is to keep concepts de-coupled as much as possible to allow the maximum flexibility of their usage. That doesn't go against OO. In fact, what I am saying is that each object must know as much as it can about itself, but as little as possible about the other objects in the system. That's what OO is all about.

                          Great discussion!

                          Comment


                          • #14
                            Thanks for the feedback constv. Certainly these discussions are rewarding, as it certainly keeps my head ticking!

                            Generally, my philosophy is to keep concepts de-coupled as much as possible to allow the maximum flexibility of their usage. That doesn't go against OO. In fact, what I am saying is that each object must know as much as it can about itself, but as little as possible about the other objects in the system. That's what OO is all about.
                            I think the overall goal is the same, its just that there are some differences between the two designs. Unless anyone else disagrees, I guess both designs are commonly used these days.

                            I feel the key differences between the two designs are that:
                            • Both have a separate data layer for the DAOs. However, one injects the DAO implementations within the Service classes. The other injects within the Domain classes (with the help of a Factory class).
                            • One would have common business rules (that are not likely to change) defined in the Service classes, while the other defines it within the Domain classes (or perhaps within a separate Manager class, but could lead to anaemic).

                            I would certainly agree that there are some Domain objects that only maintain state, effectively acting as Data Transfer Objects between the client and Domain entities. In this way the business rules are not exposed. As the Domain entities maintains behaviour (business logic) as well as state, these objects are never exposed through the Service classes. As you've stated, there are some common features that perhaps are worded differently.


                            Shah.

                            Comment

                            Working...
                            X