PDA

View Full Version : TransactionProxyFactory and ApplicationContext



newToSpring
Oct 7th, 2004, 09:25 AM
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..

eric chan
Oct 7th, 2004, 10:33 PM
post your applicationContex.xml

newToSpring
Oct 8th, 2004, 08:54 AM
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.ContextLoaderServl et</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet>
<servlet-name>webapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</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.PropertyP laceholderConfigurer">
<property name="location"><value>classpath:jdbc.properties</value></property>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerD ataSource">
<property name="driverClassName"><value>${jdbc.driverClassName}</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.DataSourceTran sactionManager">
<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.Transa ctionProxyFactoryBean">
<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.Transa ctionProxyFactoryBean">
<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>
....

irbouho
Oct 8th, 2004, 10:42 AM
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

newToSpring
Oct 8th, 2004, 02:22 PM
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)..

irbouho
Oct 8th, 2004, 02:42 PM
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

newToSpring
Oct 8th, 2004, 03:26 PM
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 ?

irbouho
Oct 8th, 2004, 04:27 PM
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:

<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

newToSpring
Oct 8th, 2004, 05:43 PM
Thanks..that seems to work for me..

springer
Oct 18th, 2004, 03:45 PM
I will realy appreciate it if you could post the final working code from your application.
Thanks