Announcement Announcement Module
Collapse
No announcement yet.
Content-Based-Routing using Message Channels vs Lazy loading - which is better ? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Content-Based-Routing using Message Channels vs Lazy loading - which is better ?

    I would like to know, from design perspective (mainly considering parameters as performance for large volume of requests, memory usage in heap, other non-functional parameters, etc), which is a better approach:

    Design-1:
    I've message incoming to a channel (say channelA). The channelA is being read by a header-value-router.
    Based on some content in the message payload, it will be routed two either of two channels (channelB or channelC).
    These two channels are in-turn being read by two separate service-activators that are POJOs (say POJO1 and POJO2) with business logic embedded in them.

    vs

    Design-2:
    I've message incoming to a channel (say channelA). The channelA is being read by a service-activator. This service activator is a simple POJO that does lazy loading either of POJO1 or POJO2 based on the content in the message payload.

    I would like to know which is a better approach from design point of view. Both POJOs (POJO1 and POJO2) have in-built business logic but the difference is how they are invoked (router+service-activators vs lazy loading).

    Thanks & Regards
    LB
    Last edited by lbvirgo; Aug 2nd, 2013, 01:29 PM.

  • #2
    As always, it depends. I am not entirely sure what you mean by lazy loading in this context, but I will assume you mean have the POJO referenced by the service activator do a new POJOx() each time.

    In general I would prefer Design-1, especially if POJOx is expensive to construct. Design-2 might be needed if POJO1 (or 2) cannot be made thread-safe without effectively single-threading messages passing through them. Good design for any spring app should strive for stateless beans, eliminating this issue and avoiding the extra memory management.

    Comment


    • #3
      Gary - Sorry, actually I meant dynamic loading

      As an example, say, my route mapping values are "value1" and "value2".
      In my property (or some configurable) file, I mention as below:
      value1=com.mycompany.test.POJO1
      value=com.mycompany.test.POJO2

      In the POJO calss that reads channelA, I put in code something like this:

      String routingValue = Properties.getValue(message.getPayload().getRoutin gValue());

      //Assume both POJO1 and POJO2 are implementing a Interface, say BasePOJOInterface
      BasePOJOInterface obj = (BasePOJOInterface)Class.forName(routingValue).new Instance();

      //invoke business method
      obj.doInvoke();


      There is a concern in my architect group that increase in number of route mapping values will increase the number of channels and in turn will be an impact on performance (i.e., having a router mapped to multiple channels and each channel being read by a service-activator will be a costly operation).
      The suggestion instead from the group is to have one common channel that will be read by a service-activator POJO and this POJO will instantiate the POJOx during "runtime" based on the routing value (present in payload) and then invoke the business method on the runtime instantiated POJOx (assuming all POJOx implement same interface)


      if POJOx is expensive to construct
      Not sure what you mean by this, but both my POJOx have only default constructors and are thread safe (i.e., no instance variables).

      So based on above details, what should be the suggested design - Design1 (multiple routing channels) OR Design2(Dynamic Loading) ?

      Pls let me know your thoughts.

      Best Regards
      LB
      Last edited by lbvirgo; Aug 2nd, 2013, 11:24 PM.

      Comment


      • #4
        Well, you said
        large volume of requests
        With design-1, you'll have a single instance of POJO1, POJO2.

        With design-2, creating (and garbage collecting) a new instance of the class for each message will likely, by far, exceed the cost of design-1's router deciding which channel to send a message to.

        The service activators don't "read" from the channel (assuming it's direct). The thread invokes the router, the router decides which channel gets the message and we send to that channel, and then invoke the service on the same thread.

        Comment


        • #5
          Thanks. I too am inclined for design-1 and need to provide enough justifications for it to the architect group.

          The service activators don't "read" from the channel
          Yes, I agree. Probably I'd put my statement in incorrect way.

          Is there a way that I go with design-2 and have only singletons of my POJOx every time I create a new instance of it during runtime ?

          I earlier thought of defining my POJOx as beans in the config file and then getting instance of them through application context.
          Something like,

          <bean id="pojo1" class="com.mycompany.test.POJO1">
          <bean id="pojo2" class="com.mycompany.test.POJO2">

          In property file define as below:
          value1=pojo1
          value2=pojo2

          In POJO class that gets invoked by channelA, get the instance of these beans (through ApplicationContext.getBean(routingValue)) based on route mapping value.

          But problem with this approach is I need to know the concrete bean class when I do appCtx.getBean(). And this in-turn is going to land me up in doing IF-ELSE kind-of code in the POJO class which I guess is a very crude way of doing things. Am I correct ?

          Thanks & Regards
          LB

          Comment


          • #6
            You don't need the concrete class; you can use

            Code:
            BasePOJOInterface pojo = context.getBean(message.getPayload().getRoutingValue(), BasePOJOInterface.class);
            Realize, however, that your service is now simply a "router", so really design-1 and design-2 are 2 slightly different implementations of the same approach; but in this case you'd be coupling the router to the service invocation.

            In design-1, these two concerns are separated. With this loosely coupled approach you gain some flexibility. For example if you decide to route on something else later, you can simply reconfigure your router. If you decide to change your interface method names etc, you simply reconfigure your context and not need any code changes.

            My general recommendation is to keep everything as loosely coupled as possible, separating concerns. Do not be guilty of "premature optimization". One of the compelling stories for SI is its flexibility; you can very easily add optimizations later, if you find you hit an issue. I'd rather take a small performance hit to gain maximum flexibility.

            Even in this case, switching between design-1 and design-2 should be rather trivial.

            Bear in mind, also, that any framework overhead tends to pale into insignificance when real application logic is performed on top of it.

            Comment


            • #7
              Thanks Gary.

              My last query on same context:

              Is it advisable to break the complete routing logic across multiple routers OR have just one router with multiple permutations & combinations of the "mapping" value ?

              As an example, say my message payload has three properties viz., "statusCode", "executionContextCode" and "messageEndpoingMnemonic"

              statusCode can have values as "CMP" and "FLD"
              executionContextCode can have values as "SCH" and "ADH"
              messageEndpoingMnemonic can have values as "ERX", "ERT", "ERP"

              My requirement is as below:
              HTML Code:
              IF "statusCode" = FLD, then invoke nullChannel
              ESLE-IF "statusCode" = CMP {
                   IF "messageEndpoingMnemonic" is ERX, invoke ERX-service-activator and place output to a channel (say "commonOutChannel")
                        {
                            IF "executionContextCode" = ADH then invoke ADH-service-activator
                            ELSE IF "executionContextCode" = SCH then invoke SCH-service-activator
                     
                        }
                   ELSE IF "messageEndpoingMnemonic" is ERT, invoke ERT-service-activator and place output to a channel (say "commonOutChannel")
                        {
                            IF "executionContextCode" = ADH then invoke ADH-service-activator
                            ELSE IF "executionContextCode" = SCH then invoke SCH-service-activator       
                        }
                  ELSE IF "messageEndpoingMnemonic" is ERP, invoke ERP-service-activator and place output to a channel (say "commonOutChannel")
                        {
                            IF "executionContextCode" = ADH then invoke ADH-service-activator
                            ELSE IF "executionContextCode" = SCH then invoke SCH-service-activator       
                        }
              }
              Now, which approach will be better:

              Approach 1:
              InChannel --> Router1 ("CMP" vs "FLD") --> Router2("ERX" vs "ERT" vs "ERT") --> service-activators (ERX-service-activator vs ERT-service-activator vs ERP-service-activator) --> commonOutChannel --> Router3("ADH" vs "SCH") ---> service-activators (ADH-service-activator vs SCH-service-activator)

              Approach 2:
              InChannel --> Router1 ("FLD|ERX|ADH" vs "FLD|ERT|ADH" vs "FLD|ERP|ADH" vs "FLD|ERX|SCH" vs "FLD|ERT|SCH" vs "FLD|ERP|SCH" vs "CMP|ERX|ADH" vs "CMP|ERT|ADH" vs "CMP|ERP|ADH" vs "CMP|ERX|SCH" vs "CMP|ERT|SCH" vs "CMP|ERP|SCH") --> nullChannel OR service-activators

              Above is just an example and in real application, I can have multiple mapping values for each router and the routing logic can get extended to multiple routers.
              To me, approach 1 should be a more preferable considering it is more flexible and fits best for "plug-and-play" design.
              However, with this approach we are ending up having multiple routers (that can increase as the routing logic becomes more complex).
              In approach 2, anytime a new mapping value is introduced, I'll have to end up having lot many combinations of of route mapping values that ultimately can lead to a lot of confusion and maintaining it will be a nightmare. The only benefit approach 2 can give is not having any more routers as the routing logic becomes more complex. One single router can take care of the logic as long as the mapping value is intelligent enough.

              Pls let me know your thoughts on each approach from a pure design perspective.

              Best Regards
              LB

              Comment


              • #8
                As we have suggested several times; please start a new thread for new questions rather than adding to an existing thread; this makes it easier for other people to find questions and answers.

                I would prefer approach 1 (however, I would use a <filter/> instead of a <router/> for CMP Vs FLD.

                Comment

                Working...
                X