Announcement Announcement Module
Collapse
No announcement yet.
Header enricher problem with a scope="prototype" bean reference Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Header enricher problem with a scope="prototype" bean reference

    Hallo all.
    I have this definition:

    <int:chain input-channel="onlineMessagePreProcessingChannel">
    <int:header-enricher>
    <int:header name="crbMessageToForward" ref="crbForwardable"/>
    </int:header-enricher>
    <int:filter discard-channel="discardOnlineEventMessageChannel" ref="onlinePreProcessingFilter" />
    <int:router ref="onlineMessageRouter" method="route" default-output-channel="ONLINE_NO_OPERATION"/>
    </int:chain>

    <bean id="crbForwardable" class="it.alten.intesasanpaolo.contratto.domain.ev ent.CrbForwardable" scope="prototype"/>

    I need that every time that a message passes through the channel onlineMessagePreProcessingChannel the header enricher puts a new instance of the referenced bean crbForwardable.

    I thought that the scope="prototype" on the bean definition would be enough, but it still does not work.

    Where is the error?

    Kind regards
    Massimo

  • #2
    Add 'aop' namespace t you configuration and change your bean definition to look like this:
    Code:
    <bean id="crbForwardable" class="it.alten.intesasanpaolo.contratto.domain.ev ent.CrbForwardable" scope="prototype">
         <aop:scoped-proxy/>
    </bean>
    Read more about it here http://static.springsource.org/sprin...ther-injection

    The bottom line is that 'prototype' will return a new instance every time you execute context.getBean(). So the filter is no different, it calls getBean() on application context and gets its own instance, but since the filter itself is singleton you end up using the same instance of the underlying bean. So scoped-proxy is the mechanism to resolve this issue.

    The bigger problem is the fact that your bean is NOT singleton which means it has state which is counter-intuitive to Messaging where processors are stateless and state is maintained in the Message, thus making message-based systems very scalable because they are inherently stateless.
    Do you want to share as to why your beans are stateful?

    Comment


    • #3
      Kind regards, It seems to work.

      >Do you want to share as to why your beans are stateful?
      This is the only bean that I use to decide if a message must be forwarded to a system or not.

      In my chain I put a reference to this bean at the beginning:

      public class CrbForwardable {
      private final static Logger logger = LoggerFactory.getLogger(CrbForwardable.class);

      private Boolean messageToForward = true;

      public CrbForwardable() {
      logger.debug("CrbForwardable constructor executed...");
      }

      public Boolean isMessageToForward() {
      return messageToForward;
      }

      public void setMessageToForward(Boolean toForward) {
      this.messageToForward = toForward;
      }

      @Override
      public String toString() {
      return new ToStringCreator(this).append("messageToForward", messageToForward).toString();
      }

      Then I have a component in the chain that evaluates some business data and change the header value:

      public abstract class HeaderModifierActivator<T extends Serializable> {
      private final static Logger logger = LoggerFactory.getLogger(HeaderModifierActivator.cl ass);

      /**
      *
      * Il metodo di cui fornire l'implementazione per la modifica dell'header
      * @return
      *
      */
      public Message<EventMessage<T>> activate(Message<EventMessage<T>> message) {
      CrbForwardable crbForwardable = (CrbForwardable) message.getHeaders().get(ContrattoConstants.CRB_ME SSAGE_TO_FORWARD);
      boolean messageToForward = isMessageToForward(message.getPayload());

      crbForwardable.setMessageToForward(messageToForwar d);

      logger.info("Settaggio della chiave di header {} a {} ", ContrattoConstants.CRB_MESSAGE_TO_FORWARD, messageToForward);

      return message;
      }


      public abstract boolean isMessageToForward(EventMessage<T> eventMessage);
      }

      The last component is a filter that evaluates the value present in the header and decide if the message is to discard or to forward:

      public class CrbForwardFilter implements MessageSelector {
      private final static Logger logger = LoggerFactory.getLogger(CrbForwardFilter.class);

      /**
      * @see org.springframework.integration.core.MessageSelect or#accept(org.springframework.integration.Message)
      */
      @Override
      public boolean accept(Message<?> message) {
      CrbForwardable crbForwardable = (CrbForwardable) message.getHeaders().get(ContrattoConstants.CRB_ME SSAGE_TO_FORWARD);

      logger.info("crbForwardable {}", crbForwardable);

      logger.info("Filtro per il forward verso CRB; crbMessageToForward {}", crbForwardable.isMessageToForward());
      return crbForwardable.isMessageToForward();
      }

      }

      I think that the design is clean and scalable, but I don't know if the header enricher was the best candidate component.

      Any suggestion?
      Kind regards
      Massimo

      Comment


      • #4
        In Messaging Architecture - Content Enricher pattern http://www.eaipatterns.com/DataEnricher.html is the right pattern to manage the state of the Message. One of the compelling reason is simply because such data could easily be serialized/transformed and transported to a different remote system where your statefull Java object might not be available or the system might not be Java based system.
        In any event, I would stay away from introducing stateful endpoints other then the once that are stateful by definition (e.g., QueueChannel, Aggregator, Resequencer etc.)

        Comment


        • #5
          Sorry, i overlooked the fact that what you were doing is injecting stateful bean into the header (not creating stateful endpoint)

          Anyway, its all good now and i guess with scoped-proxy its working for you. Right?

          Comment


          • #6
            Writing

            <int:header name="crbMessageToForward" expression="@crbForwardable"/>

            seems to do the trick without needing aop tricks.

            Comment


            • #7
              a new instance every time you execute context.getBean(). So the filter is no different, it calls getBean() on application context and gets its own instance, but since the filter itself is singleton you end up using the same instance of the underlying bean. what you were doing is injecting stateful bean into the header

              Comment


              • #8
                I'm sorry, I thought that the subject of the thread was about injecting a prototype bean into a header.

                About filter, how about using it with an expression (replace "filterMethod" with the real method of the filter):

                <int:filter discard-channel="discardOnlineEventMessageChannel" expression="@onlinePreProcessingFilter.filterMetho d(payload)" />

                This would use a new instance of onlinePreProcessingFilter for each call.

                Comment

                Working...
                X