Thursday, 17 February 2011

Spring Transaction Manager with AOP


<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
</aop:config>

Tuesday, 1 February 2011

Spring Transaction Management


Spring Framework supports:
  • Programmatic transaction management.
  • Declarative transaction management.



Programmatic configuration:
-----------------------------------
In this approach Hibernate properties are set in the confguration object through its setProperty() method:


public Configuration setProperty(String propertyName, String propertyValue)


Configuration cfg = new Configuration()
    .setProperty("hibernate.connection.url", "jdbc:hsqldb:hsql://localhost/hiberdb")
    .setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
    .setProperty("hibernate.connection.username", "sa")
    .setProperty("hibernate.connection.password", "")
    .setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");


Or you create a java.Util.Properties object and pass it to Configuration constructor.


Or public Configuration setProperties(Properties properties);
  
To add resource files or hbm files:



config.addResource("com/packtpub/springhibernate/ch04/Student.hbm.xml");


Declarative configuration:
--------------------------------
In declarative configuration you load hibernate.properties file in classpath with key=value configuration.
Content in properties file will be as following:

#hibernate configuration
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:hsql://localhost/hiberdb
hibernate.connection.username=sa
hibernate.connection.password=
hibernate.pool_size=5
hibernate.show_sql=false
hibernate.dialect= org.hibernate.dialect.HSQLDialect

When using this approach, you need to introduce mapping fles to Hibernate programmatically, like this:
config.addClass(Student.class);

Or using XML file configuration as follwoing:

The following code shows a simple XML confguration fle with  
the basic confguration entries:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
          "http://hibernate.sourceforge.net/hibernate-configuration 
          -3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <!-- Hibernate Properties -->
    <property name="connection.driver_class"> org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:hsql://localhost/hiberdb</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"> </property>
    <property name="pool_size">5</property>
    <property name="show_sql">false</property>
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
    <!-- Mapping files -->
    <mapping resource="com/packtpub/springhibernate/ch04/ 
                                      Student.hbm.xml"/>
    <mapping resource="com/packtpub/springhibernate/ch04/ 
                                      Teacher.hbm.xml"/>
    <mapping resource="com/packtpub/springhibernate/ch04/ 
                                       Course.hbm.xml"/>
  </session-factory>
</hibernate-configuration>





Bean-Life Cycle :- InitializingBean, DisposableBean, BeanPostProcessor - BeanNameAware



Spring InitializationBean Marker Interface

There are two ways you can achive the initialization work after all necessary properties on the bean are set by the container.
1) use 'init-method' in XML configuration 
You can do initialization work in init() method.
<bean id="testInitBean" class="com.techfaq.TestBean" init-method="init"/>
public class TestBean {

public void init() {
// do some initialization work 
}
}

2) Implementing the org.springframework.beans.factory.InitializingBean interface 
You can do initialization work in afterPropertiesSet() method.
void afterPropertiesSet() throws Exception;
<bean id="testInitBean" class="com.techfaq.TestBean" />
public class TestBean {

public void afterPropertiesSet() {
// do some initialization work 
}
}


Spring DisposableBean Marker Interface

Implementing the org.springframework.beans.factory.DisposableBean interface allows a bean to get a callback when the container containing it is destroyed.
There are two ways you can achive the destroy.
1) use 'destroy-method' in XML configuration 
You can do cleanup work in cleanup() method.
<bean id="testDestBean" class="com.techfaq.TestBean" destroy-method="cleanup"/>
public class TestBean {

public void cleanup() {
// do some destruction work (like releasing pooled connections) 
}
}

2) Implementing the org.springframework.beans.factory.DisposableBean interface allows a bean to get a callback when the container containing it is destroyed 
void destroy() throws Exception;
<bean id="testDestBean" class="com.techfaq.TestBean" />
public class TestBean {

public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}

Spring BeanPostProcessor

The interface BeanPostProcessor allows custom modification of all new bean instance like for example making for marker interfaces or wrapping them with all proxies. The advance of interface BeanPostProcessor is that it auto-detect BeanPostProcessor beans in their bean definations and apply all beans before any others get created.

StudentBean.java
package com.roseindia.common;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
class StudentBean implements BeanPostProcessor {

    public Object postProcessBeforeInitializtion(Object bean, String beanName)
                        throws BeansException {
               return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
                        throws BeansException {
               System.out.println("Initialized Bean : " + beanName);
               return bean;
    }
}
AppMain.java
package com.roseindia.common;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class AppMain {

        public static void main(String[] args) {
                ApplicationContext context = new ClassPathXmlApplicationContext(
                                "context.xml");
                context.getBean("student");
        }
}
context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  
  <bean id="student" class="java.lang.String">
  </bean>
  
  <bean id="studentBean" class="com.mayank.common.StudentBean" />
</beans>

When you run this application it will display message as shown below:


Initialized Bean : student


Spring BeanNameAware

The Interface BeanNameAware is implemented by beans that help to aware of their bean name in bean factory. The setBeanName method set the name for the bean in the bean factory. In this example you will see how to implement BeanNameAware in your bean class.
StudentBean.java

package com.roseindia.common;
import org.springframework.beans.factory.BeanNameAware;
class StudentBean implements BeanNameAware {
        private String name;

        public void setBeanName(String name) {
                this.name = name;
        }

        public void showBean() {
                System.out.println("Bean name : " + this.name);
        }
}
AppMain.java

package com.roseindia.common;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class AppMain {

        public static void main(String[] args) {
                ApplicationContext context = new ClassPathXmlApplicationContext(
                                "context.xml");
                StudentBean bean = (StudentBean) context.getBean("studentBean");
                System.out.println(context);
                bean.setBeanName("satya");
                bean.showBean();
        }
}
context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  <bean id="studentBean" class="com.roseindia.common.StudentBean" />
</beans>

When you run this application it will display message as shown below:


Bean name : satya

Spring – Bean Scopes


Bean scope is used to decide which type of bean instance should be return to the caller. Here’s 5 types of bean scopes supported :
  • singleton – Return a single bean instance per Spring IoC container
  • prototype – Return a new bean instance each time when requested
  • request – Return a single bean instance per HTTP request. *
  • session – Return a single bean instance per HTTP session. *
  • globalSession – Return a single bean instance per global HTTP session. *
In most cases, you may only deal with the Spring’s core scope – singleton and prototype, and the default scope is singleton.
<bean id="customerService" class="com.mkyong.customer.services.CustomerService" scope="prototype"/>

Bean configuration file, no bean scope is specified, default to singleton.
<bean id="customerService" 
         class="com.mkyong.customer.services.CustomerService" />
It is same as :

<bean id="customerService" class="com.mkyong.customer.services.CustomerService" 
singleton="true"/>

Using Annotation:

@Service
@Scope("prototype")
public class CustomerService{}


Enable the auto scanning:

<context:component-scan base-package="com.mkyong.customer" />



DelegatingVariableResolver

Spring provides a custom JavaServer Faces VariableResolver implementation that extends the standard Java Server Facesmanaged beans mechanism which lets you use JSF and Spring together. This variable resolver is called as DelegatingVariableResolver

It is a badly documented issue in Spring 2.5 ... 
Well, DelegatingVariableResolver is the way to integrate spring with JSF 1.1 by using a variable-resolver in faces-config.xml, like this:

HTML Code:
<application> 
  <variable-resolver> 
    org.springframework.web.jsf.DelegatingVariableResolver 
  </variable-resolver> 
</application>
But this is a deprecated method in JSF 1.2.

So, Spring 2.5 introduced a new way by using SpringBeanFacesELResolver like this:
HTML Code:
<application> 
  <el-resolver> 
org.springframework.web.jsf.el.SpringBeanFacesELResolver 
  </el-resolver> 
</application>

Spring – Auto-Wiring Beans in XML


In Spring framework, you can wire your beans automatically with auto-wiring feature. To enable it, you need to specify the auto-wiring mode in the autowire attribute of <bean>

Auto-wiring modes

In Spring, 5 Auto-wiring modes are supported.
  • no – No auto-wiring.
  • byName – Auto-wire a bean whose the name is same as the property.
  • byType – Auto-wire a bean whose data type is compatible with the property.
  • constructor – Auto-wire a bean whose date type is compatible with the property constructor argument.
  • autodetect – If a default constructor with no argument is found, it will auto-wire by data type. Otherwise, it will auto-wire by constructor.
In case of any ambiguity in ‘byType’ or ‘constructor’ mode, an UnsatisfiedDependencyException will be thrown.
P.S The default mode is ‘no’.

A Customer and Person object for the demonstration.

package com.mkyong.common;
 
public class Customer 
{
 private Person person;
 private int type;
 private String action;
 
 //getter and setter methods
 
       @Override
 public String toString() {
  return "Customer [action=" + action + ", person=" + person + 
                          ",type=" + type + "]";
 }
 
}
package com.mkyong.common;
 
public class Person 
{
 private String name;
 private String address;
 private int age;
 
 //getter and setter methods 
}

1. ‘no’ auto-Wiring mode

This is the default mode, you have to wire your bean explicitly by using the ‘ref’ attribute.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
 <bean id="CustomerBean" class="com.mkyong.common.Customer">
        <property name="person" ref="PersonBean" />
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="PersonBean" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>

2. ‘byName’ auto-Wiring mode

It will auto-wire a bean whose name is same as the property.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" autowire="byName">
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="PersonBean" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>
Run it
Customer [action=buy, person=null, type=1]
You will notice that the person property is not auto-wire, the person is still ‘null’, this is because the bean name ‘PersonBean’ is mismatch, it should be ‘person’. In ‘byName’ mode, the name of the auto-wire bean and the property name have to be exactly same (case sensitive as well).
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" autowire="byName">
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="person" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>
Run it again
Customer [action=buy, 
person=Person [address=address 123, age=28, name=mkyong], type=1]
Problem
In most cases, it is not practical to always make the name of the target bean the same as your property. In the end, you will always have a mixture of explicit wiring and auto-wiring environment.

3. ‘byType’ auto-Wiring mode

It will auto-wire a bean whose data type is same as the property.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" autowire="byType">
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="person" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>
Run it
Customer [action=buy, 
person=Person [address=address 123, age=28, name=mkyong], type=1]
Problem
Assume you have two person’s Beans as following :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" autowire="byType">
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="PersonBean1" class="com.mkyong.common.Person">
 <property name="name" value="mkyong1" />
 <property name="address" value="address 1" />
 <property name="age" value="28" />
  </bean>
 
  <bean id="PersonBean2" class="com.mkyong.common.Person">
 <property name="name" value="mkyong2" />
 <property name="address" value="address 2" />
 <property name="age" value="28" />
  </bean>
 
</beans>
Run it, you will hit the following error message
org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No unique bean of type [com.mkyong.common.Person] is defined: 
expected single matching bean but found 2: [PersonBean1, PersonBean2]
The problem is sometimes there will be more than one beans are match with ‘byType’ criteria. In this case, Spring will throw an UnsatisfiedDependencyException exception.

4. ‘constructor’ auto-Wiring mode

It will auto-wire a bean whose date type is compatible with the property constructor argument. In this case, person bean will inject via Customer’s constructor automatically.
- Add a constructor to Customer class
package com.mkyong.common;
 
public class Customer 
{
 private Person person;
 private int type;
 private String action;
 
 public Customer(Person person) {
  this.person = person;
 }
        //getter and setter method
 @Override
 public String toString() {
  return "Customer [action=" + action + ", person=" + person + 
                         ", type=" + type + "]";
 }
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" autowire="constructor">
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="PersonBean" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>
Run it
Customer [action=buy, 
person=Person [address=address 123, age=28, name=mkyong], type=1]
Problem
The ‘constructor’ mode is facing the same problem with ‘byType’ auto-wire mode, if more than one beans are matched, Spring will throw an UnsatisfiedDependencyException exception as well. In addition, multiple constructors in a class may causing the ambiguity in constructor argument matching, in this case you will spend more time on resolving the issue.

5. ‘autodetect’ auto-Wiring mode

If a default constructor with no argument is found, it will auto-wire by data type. Otherwise, it will auto-wire by constructor.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" autowire="autodetect">
 <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="PersonBean" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>
Problem
It has the same problem with ‘byType’ and ‘constructor’, the worst is you may need to find out which mode is execute now.

Good Practice

It’s always good to combine the ‘auto-wire’ and ‘dependency-check’ feature together to make sure the property is auto-wire successfully.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <bean id="CustomerBean" class="com.mkyong.common.Customer" 
 autowire="autodetect" dependency-check="objects">
 
        <property name="action" value="buy" />
 <property name="type" value="1" />
  </bean>
 
  <bean id="PersonBean" class="com.mkyong.common.Person">
 <property name="name" value="mkyong" />
 <property name="address" value="address 123" />
 <property name="age" value="28" />
  </bean>
 
</beans>

Conclusion

In my opinion, this Spring ‘auto-wiring’ feature will reduce the readability of your bean configuration, and you even do not know which beans will wired from the bean configuration file, you are totally out of control of what will happened.
In practice, i recommend applying ‘auto-wiring’ only in small and simple component dependencies applications.