Announcement Announcement Module
Collapse
No announcement yet.
TransactionProxyFactory and ApplicationContext Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • TransactionProxyFactory and ApplicationContext

    Hi

    I have the following scenario

    I have a webapp in which the web.xml has an applicationcontext created using contextloaderservlet with a set of xml files defining the beans.
    I also refer in the webapp another jar file in which a class creates another applicationcontext using classpathapplicationcontext with a set of xml files definfing beans.

    In one of the scenario a MgrbeanA invoked by a controller in the webapp is obtained from TransactionProxyFactory and the MgrbeanA further calls another MgrBeanB defined in the applicationcontext that was created by the class in the jar file which is also obtained from a TransactionProxyFactory.
    In effect the code looks something like this in the MgrBeanA in the WebApp

    doSomething {
    performActionOneinDB();
    callMgrBeanBInJarToPerformActionInDB();
    performActionTwo();
    }

    The issue i'm facing currently is , if there is an exception raised in performActionTwo() i expect the whole operation being rolled back, but the actually what happens is the callMgrBeanInJarToPerformActionInDB(); is committed irrespective of what happens in MgrbeanA.
    As these are two different applicationcontexts the datasources referred in these contexts are also different.

    Is my approach correct, should i be,
    1. not define datasources seperate if i want to propogate the transaction
    2. merge my application contexts into one
    3. make the application contexts hierarchial

    i tried to read thru the documentation and the forum posts, but i'm not sure of which approach to take..

    also i have another clarification, if i want to have an applicationcontext defined in the webapp so that the cotroller can invoke it, how do i ensure the other applicationcontexts i define will be part of the appcontext i defined in webapp, and how do i access the beans if i dont have servletcontext available else where.

    can any one help me out on this...thanks in advance..

  • #2
    post your applicationContex.xml

    Comment


    • #3
      This is how my web.xml looks like
      <web-app>
      <display-name>MyWebApp</display-name>

      <description>MyWebApp</description>

      <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
      /resources/applicationContext-DataAccess.xml
      /resources/applicationContext-Common.xml
      /resources/applicationContext-Mgr.xml
      </param-value>
      </context-param>

      <servlet>
      <servlet-name>context</servlet-name>
      <servlet-class>org.springframework.web.context.ContextLoade rServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
      </servlet>

      <servlet>
      <servlet-name>webapp</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherSe rvlet</servlet-class>
      <load-on-startup>2</load-on-startup>
      </servlet>

      <servlet-mapping>
      <servlet-name>webapp</servlet-name>
      <url-pattern>*.do</url-pattern>
      </servlet-mapping>
      </web-app>

      this is my applicationContext-DataAccess.xml
      <beans>
      <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
      <property name="location"><value>classpath:jdbc.properties</value></property>
      </bean>

      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverM anagerDataSource">
      <property name="driverClassName"><value>${jdbc.driverClassNa me}</value></property>
      <property name="url"><value>${jdbc.url}</value></property>
      <property name="username"><value>${jdbc.username}</value></property>
      <property name="password"><value>${jdbc.password}</value></property>
      </bean>

      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSou rceTransactionManager">
      <property name="dataSource"><ref local="dataSource"/></property>
      </bean>
      </beans>

      the applicationContext-Mgr.xml defines the MgrbeanA and the applicationContext-Common.xml some support beans
      the following is the definition of the MgrbeanA

      <bean id="MgrbeanA" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
      <property name="transactionManager">
      <ref bean="transactionManager"/>
      </property>
      <property name="target">
      <ref local="MgrbeanATargetBean"/>
      </property>
      <property name="transactionAttributes">
      <props>
      <prop key="*">PROPAGATION_REQUIRED</prop>
      </props>
      </property>
      </bean>

      <bean id="MgrbeanATargetBean" class="com.test.MgrbeanA">
      <property name="appResource">
      <ref bean="appResourceBean"/>
      </property>
      <property name="basicInfoDao">
      <ref local="basicInfoDaoBean"/>
      </property>
      </bean>
      ....

      As i have mentioned earlier, in the method doSomething() in MgrbeanA, calls MgrBeanB which is in a jar file.
      It gets the MgrBeanB from a static class in the jar MyBeanProvider, which looks like this


      public static ApplicationContext ac;
      public static final String CONFIG_LOCATION_PATH = "classpath:";

      protected static void initApplicationContext() {
      ArrayList locs = new ArrayList();

      locs.add( CONFIG_LOCATION_PATH + "applicationContext-DataAccess.xml" );
      locs.add( CONFIG_LOCATION_PATH + "applicationcontext-OtherMgrs.xml" );
      locs.add( CONFIG_LOCATION_PATH + "applicationcontext-Support.xml" );

      ac = new FileSystemXmlApplicationContext( (String[]) locs.toArray( new String[locs.size()] ) );
      }

      public static MgrBeanB getMgrBeanB() {
      if ( ac == null ) {
      initApplicationContext();
      }

      return (MgrBeanB) ac.getBean( "MgrBeanB" );
      }

      here the applicationContext-DataAccess.xml is the same as the one mentioned above.
      The applicationcontext-OtherMgrs.xml defines the MgrBeanB, and looks like this


      <bean id="MgrBeanB" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
      <property name="transactionManager">
      <ref bean="transactionManager"/>
      </property>
      <property name="target">
      <ref local="MgrBeanBTargetBean"/>
      </property>
      <property name="transactionAttributes">
      <props>
      <prop key="*">PROPAGATION_REQUIRED</prop>
      </props>
      </property>
      </bean>

      <bean id="MgrBeanBTargetBean" class="com.test.MgrBeanB">
      <property name="appResource">
      <ref bean="appResourceBean"/>
      </property>
      <property name="basicInfoDao">
      <ref local="basicInfoDaoBean"/>
      </property>
      </bean>
      ....

      Comment


      • #4
        The issue i'm facing currently is , if there is an exception raised in performActionTwo() i expect the whole operation being rolled back, but the actually what happens is the callMgrBeanInJarToPerformActionInDB(); is committed irrespective of what happens in MgrbeanA.
        your methods are not wrapped in the same transaction because you are using different Spring Contexts / DataSource / Tranaction Managers...

        Is there any reason why you are using two ApplicationContexts?
        If possible, you may remove your singleton MyBeanProvider, and configure all your beans using IoC. Using only one singleton (Spring) will, for sure, improve your application design / maintenability / ...

        Is my approach correct, should i be,
        1. not define datasources seperate if i want to propogate the transaction
        2. merge my application contexts into one
        3. make the application contexts hierarchial
        1. Yes
        2. It depends on your project
        3. same as 2.

        HTH

        Comment


        • #5
          Hi irbouho

          Thanks.

          the reason i had two application contexts was to ensure that the beans defined in the second application context are retrieved from one place ie the MyBeanProvider, and refer to the bean instances in code rather than in the bean config.

          well looks like i'm better off with one application context and using spring to wire all the necessary dependencies for now..

          one question though .. how to i access this applicationcontext created thru the contextloaderservlet as defined in web.xml, throughout my application, such as an helper class some where down the line, to get beans from it(programmatically)..

          Comment


          • #6
            one question though .. how to i access this applicationcontext created thru the contextloaderservlet as defined in web.xml, throughout my application, such as an helper class some where down the line, to get beans from it(programmatically)..
            One small hack I used before is to make your MyBeanProvider Singleton imlpements BeanFactoryAware / ApplicationContextAware and configure it inside your applicationContext.xml.
            MyBeanProvider will then delegate bean creation to BeanFactory / ApplicationContext.

            HTH

            Comment


            • #7
              let's say in the following scenario, i have a controller that delegates methods to a MgrBean (which is created thru the bean defintion of the controller) and the Mgr needs to call the Singleton, how do i access the singleton(if it is defined in applicationcontect.xml and is ApplicationContextAware), should i make the singleton a member of the Mgr Bean and define it as part of the Mgr Bean definition so spring instantiates it or can i access a getInstance static method on the Class of the Singleton ?

              Comment


              • #8
                newToSpring,

                As I said, my code was a hack, and it should be avoided whenever you can. Now, what I am trying to explain is how to minimize the refactoring needed to make your existing code integrate with Spring IoC.

                1. should i make the singleton a member of the Mgr Bean and define it as part of the Mgr Bean definition
                This seems to be an excellent choice. However, If objects created by your singleton are POJOs, you have better to configure them inside your application.xml and add respective properties to your MgrBean.

                2. can i access a getInstance static method on the Class of the Singleton
                You can configure MyBeanprovider inside your applicationContext using factory-method. Spring has build-in support for such case:
                Code:
                <bean id="myBean"
                      class="MyBeanProvider"
                      factory-method="getInstance"/>
                You can also specify if Spring should manage this been as a prototype or singleton.
                Beans that are managed by Spring need to declare a reference to myBean, while classes that do not have access to your application context can use MyBeanProvider.getInstance().

                Since you are loading the applicationContext using ContextLoaderListener/ ContextLoaderServlet, there should be no problem with a class calling MyBeanProvider.getInstance() before the ApplicationContext has been injected by Spring inside it. You should however pay attention to using MyBeanprovide outside of a web application.

                HTH

                Comment


                • #9
                  Thanks..that seems to work for me..

                  Comment


                  • #10
                    Could you please post the final working code please?

                    I will realy appreciate it if you could post the final working code from your application.
                    Thanks

                    Comment

                    Working...
                    X