Posts Tagged ‘spring framework

14
Apr
10

Declarative Transactions Using Spring Framework

This page demonstrates very simple 1 resource (Local Transaction) commit and roll-back capabilities of the spring framework. The example on this page is heavy on practice and light on theory. For more information about spring transaction please check the resources section below for spring framework documentation.

Background

Based on the default behavior, when the application throws a run time exception any method that is defined to be transactional issues a roll-back on whatever resource is currently participating in the transaction. To define a method as transactional just put an @Transactional annotation before it.

Requirements

  • Java 5
  • MySQL installed and configured (not required if you just want to follow along)
  • Maven – (tutorial available on the right nav)
  • Basic understanding of Transactions

Implementation

The following example will demonstrate the transaction capabilities of the spring framework. Consider it a very basic “hello world” program for transactional code.

First step… Create the table… Its important that you specify the InnoDB engine. Otherwise the table will not support transactional capabilities.

Issue the following create statement in the mySQL database. If you don’t have access to a database to do this then just follow along with me below.

CREATE TABLE `test`.`test_table` (
`id` SMALLINT NOT NULL AUTO_INCREMENT ,
`data` TEXT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB

The Second step is to create a project using Maven archetype. Open up the command prompt and navigate to an empty directory.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart
groupId: com.test
artifactId: springTXTest

Answer the rest of the questions with defaults “Just hit the enter key”

Next, add a couple of entries in the dependencies section. Use the following pom.xml file as a guide. The 2 additional dependencies you need are the spring framework 2.5.5 and the mysql jdbc driver files. Both of these items are available using the maven central repository.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelversion>4.0.0</modelversion>
  <groupId>com.test</groupId>
  <artifactId>springTXTest</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>springTXTest</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>2.5.5</version>
    </dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.9</version>
	</dependency>
  </dependencies>
</project>

The applicationContext sets up the data source and transaction manager. Replace the database url, username, password “xxxx” with actual values.

src/main/resources/com/test/applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<!-- The following <span class="hiddenGrammarError" pre="following ">is used</span> for the @Repository, @Component, @Service, @Controller -->
	<context:component-scan base-package="com.test"></context:component-scan>

<!-- The following <span class="hiddenGrammarError" pre="following ">is used</span> for the @Autowired, @Required, @Resource etc... -->
	<context:annotation-config></context:annotation-config>

<!-- The following <span class="hiddenGrammarError" pre="following ">is used</span> for the @Transactional -->
	<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>

<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	mysql.jdbc.Driver">
	xxxx:3306/test">
	<property name="username" value="xxxx"></property>
	<property name="password" value="xxxx"></property>
<!--<span class="hiddenSpellError" pre=""-->bean>

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

The following is just an interface.

src/main/java/com/test/TestTransactionDataManager.java

package com.test;

public interface TestTransactionDataManager {
	public abstract Number writeData(String data);
}

The following DataManager inserts a row into the test_table using SimpleJdbcInsert. Since SimpleJDBCInsert is aware of any ongoing transactions the insert will happen in a transaction safe way. You could also use JdbcTemplate to achieve the same result.

src/main/java/com/test/TestTransactionDataManagerImpl.java

package com.test;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;

/**
 * This data manager is used to test the transactional capabilities
 * of the spring framework. The code below is not marked as transactional
 * however it participates in one when called from a transactional method.
 */
@Repository("testTransactionDataManager")
public class TestTransactionDataManagerImpl implements TestTransactionDataManager {
	private SimpleJdbcInsert simpleInsert;

	@Required
	@Autowired
	public void setDataSource(DataSource dataSource) {
		simpleInsert = new SimpleJdbcInsert(dataSource).withTableName(
				"test_table").usingGeneratedKeyColumns("id");
	}
	/**
	 * Responsible for writing data to a transactional resource.
	 * @param data
	 */
	public Number writeData(String data) {
		Map<string, object=""> parameters = new HashMap<string, object="">(1);
        parameters.put("data", data);
        Number newId = simpleInsert.executeAndReturnKey(parameters);
        return newId.longValue();
	}
}

Just an interface…

src/main/java/com/test/TestTransactionModel.java

package com.test;

public interface TestTransactionModel {
	public abstract void writeDataWithTx();
	public abstract void writeDataWithOutTx();
	public abstract void writeDataWithMultipleCalls();
}

This is our Model class. The model layer is a natural place to define unit of work. Model methods are called from “control layer” in the MVC architecture. (Struts actions, SpringMVC Command, or Servlets) THERE SHOULD BE AT MOST ONE call to a transaction enabled model method to get a the “unit of work” behavior. Otherwise if you have more than one call to these methods and one succeeds and the other fails you will not get the “unit of work” behavior. Please keep this in mind… Only one call to a transactional method from the “control layer”.

src/main/java/com/test/TestTransactionModelImpl.java

package com.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("testTransactionModel")
public class TestTransactionModelImpl implements TestTransactionModel {
	private TestTransactionDataManager testTransactionDataManager;

	/**
	 * This method will throw a runtime exception and the data will be rolled
	 * back.
	 */
	@Transactional  // remember @Transaction for public methods only!
	public void writeDataWithTx() {
		System.out.println("writing data within a transaction");
		Number number = testTransactionDataManager.writeData("writeDataWithTx");
		System.out.println("wrote item: " + number);
		System.out.println("issuing runtime exception in transactional method");
		throw new RuntimeException();
	}

	/**
	 * This method will throw a runtime exception and the data will still be
	 * persisted.
	 */
	public void writeDataWithOutTx() {
		System.out.println("writing data without a transaction");
		Number number = testTransactionDataManager.writeData("writeDataWithTx");
		System.out.println("wrote item: " + number);
		System.out.println("issuing runtime exception. you will still see this record in db.");
		throw new RuntimeException();
	}

	/**
	 * This method tests the capability of calling another method that is
	 * declared to be transactional where the second method throws an exception
	 * but this method still commits.
	 */
	@Transactional
	public void writeDataWithMultipleCalls() {
		try {
			writeDataWithTx();
		} catch(RuntimeException ex) {
			System.out.println("suppressing runtimeexception and committing anyway you should see this record in DB");
		}
	}
	@Autowired
	@Required
	public void setTestTransactionDataManager(
			TestTransactionDataManager testTransactionDataManager) {
		this.testTransactionDataManager = testTransactionDataManager;
	}
}

App.java#main() method is our entry point into the system. The doIt() method will call methods on the model layer. Catch any exceptions and continue processing the rest of the model methods.

src/main/java/com/test/App.java

package com.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	private ApplicationContext context = new ClassPathXmlApplicationContext("com/test/applicationContext.xml");

	public void doIt() {
		TestTransactionModel model = (TestTransactionModel)context.getBean("testTransactionModel");

		try {
			model.writeDataWithOutTx();
		} catch (RuntimeException ex) { // do nothing }

		try {
			model.writeDataWithTx();
		} catch (RuntimeException ex) { // do nothing }

		try {
			model.writeDataWithMultipleCalls();
		} catch (RuntimeException ex) { // do nothing }
	}

	public App() {
		doIt();
	}
	public static void main(String[] args) {
		new App();
	}
}

Results

The following is the console output of the program.

writing data without a transaction
wrote item: 1
issuing runtime exception. you will still see this record in db.
writing data within a transaction
wrote item: 2
issuing runtime exception in transactional method
writing data within a transaction
wrote item: 3
issuing runtime exception in transactional method
suppressing runtimeexception and committing anyway you should see this record in DB

Checking the database you will see that only row id’s 1 and 3 got saved on the table.

Resources

That’s all for now!

28
Oct
09

Using Annotations to Autowire beans in the Spring Framework

The new features of the Java 5 framework include Annotations. Annotations is a sort of meta-data about classes. These new Java 5 feature allow the developer to describe additional information about java classes methods and fields. This additional metadata can be used to generate boilerplate code used to configure the application at runtime.

Spring Framework and XML

If you have worked with the spring framework long enough you get to know that a lot of configuration is xml based. While this is great for very large application it can get to be a hassle for small project. Also if you are creating a rapid proto-type you want your codeing experience to be free-flowing. You dont really want to create a class and then have to write xml code inject it into another class.

In the following tutorial we will cover the basics of how to create a simple standalone spring application that will auto-wire itself with very little xml configuration. Spring XML configuration will be 2-3 lines of code  (not including the header).

Start a new project

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart

Answer the rest of the questions like this:
Group ID: com.test
Artifact Id: springAnnotation

cd springAnnotation

We first start out by creating a plain old Java Application in the eclipse project. You can go ahead and create one and put a Maven 2 pom.xml file seen below.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.test</groupId>
	<artifactId>springAnnotation</artifactId>
	<packaging>jar</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>springAnnotation</name>
	<url>http://maven.apache.org</url>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring</artifactId>
			<version>2.5.5</version>
		</dependency>
	</dependencies>
</project>

Regenerate the project

Regenerate the project in eclipse by typing: mvn eclipse:clean eclipse:eclipse

Annotation Based configuration

Create the resources folder if it does not exist. and create the applicationContext.xml file.

src/main/resources/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
 
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 
http://www.springframework.org/schema/context
 
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
    <context:annotation-config/>

	<context:component-scan base-package="com.test"/>
 
</beans>

@Required

Indicates that this field is required to be injected. If this bean did not get injected by the time the injection step completes then the container shuts down and prints an error message.

@Autowired or @Resource (JSR-250) method

Used on setters to auto inject dependencies into beans. Prefer using @Resource because it is a Java Standard.

@Qualifier

Used for fine tuning of what gets selected for injection.

Example Application

src/main/java/com/test/ClassA.java

package com.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Component;

@Component("classAA")
public class ClassA {
	private IClassB classB;

	public IClassB getClassB() {
		return classB;
	}
	@Autowired
	@Required
	public void setClassB(IClassB classB) {
		this.classB = classB;
	}

}

src/main/java/com/test/ClassB.java

package com.test;

import org.springframework.stereotype.Component;

@Component
public class ClassB implements IClassB {

	public void testMethod() {
		System.out.println("\n\n\nSpring Annotations are Easy!!!\n\n\n");
	}
}

src/main/java/com/test/IClassB.java

package com.test;

public interface IClassB {
	public abstract void testMethod();
}

The following is a test class that will print the results to the console.

src/test/java/com/test/AppTest.java

package com.test;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.CollectionUtils;

public class AppTest extends TestCase {
	public AppTest(String testName) {
		super(testName);
	}

	public static Test suite() {
		return new TestSuite(AppTest.class);
	}

	public void testApp() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		System.out.println(CollectionUtils.arrayToList(context
				.getBeanDefinitionNames()));
		ClassA classA = (ClassA) context.getBean("classAA");
		classA.getClassB().testMethod();
	}
}

Run the test

At the root directory for the project type the following.

mvn test

This should print out the following to the console:

[org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, classAA, classB]



Spring Annotations are Easy!!!



Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.338 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Sun Jun 06 22:03:36 EDT 2010
[INFO] Final Memory: 15M/159M
[INFO] ------------------------------------------------------------------------

Component Scanning

In the previous section we reviewed how to inject beans that are already defined in the application Context injected into new beans using @Autowired or @Resource.

In this section we will go over how those beans got into the application context in the first place.

The magic starts with specifying a comma separated list of packages that will be scanned for Annotations. Put the following line into the spring configuration file.


<context:component-scan base-package="test"/>

The system will scan the test package for components that should be added to the application context. There is no need to define them in an xml file. You do need to put the following annotation at the class level so they get recognized.

Component Scan Annotations

@Repository – this was added as part of Spring 2.0 to indicate that this class serves the role of a datamanager or DAO.
@Component - this annotation indicates that this class is a general purpose spring managed bean. The @Repository, @Service, and @Controller are specializations of this base bean. You can always use @Component for all beans, but its not a good idea.
@Service – this annotation indicates that this is a class that contains Business Logic and serves as the Service/Model bean.
@Controller – Typically indicates that this class is used as a Controller in a Web Application.

Naming Component Scanned Beans

By default unless other wise specified a bean name will be the same name as the class however the first letter will not be capatalized. For example the following class will appear as movieFinderImpl

@Repository
public class MovieFinderImpl implements MovieFinder {
//...
}

If you want to specify a custom name for a bean all you need to specify is the following and the bean will be known as specialMovieFinder in the spring container.

@Repository("specialMovieFinder")
public class MovieFinderImpl implements MovieFinder {
//...
}

Constructor Injection

If your beans use constructor injection instead of setter injection you can still use annotations. Just use the @Qualifier annotation for each constructor parameter.

@Component("classAA")
public class ClassA {
    private IClassB classB;
 
    public IClassB getClassB() {
        return classB;
    }

    @Autowired
    public ClassA(@Qualifier("classB") IClassB classB) {
        this.classB = classB;
    }
}

Scalar Values

At this moment it does not look like you can specify scalar values based on annotations. But after a few minutes of thinking this thru, why would you want to? You can always set the scaler value in the constructor or where you are defining the attributes. With spring 3 you may use @Value annotation.




Follow

Get every new post delivered to your Inbox.

Join 34 other followers