The modern Spring Framework is an extensive suite of framework "stacks" based on architectural concepts that go back to the start of the century. The Spring Framework first came to prominence with Expert One-on-One J2EE Design and Development, Rod Johnson, in 2002. Spring's implementation of the Inversion of Control (IoC) principle, sometimes also known as Dependency Injection (DI), was a breakthrough in enterprise application design and development. The Spring IoC container provided a simple way of configuring objects (JavaBeans) and injecting dependencies through constructor arguments, factory methods, object properties, or setter methods. We have already seen the @PersistenceContext
annotation in our DAO layer that is used by Spring to identify whether an EntityManager
object should be injected into the GenericDaoImpl
class. The sophisticated configuration options available make the Spring Framework a very flexible foundation for enterprise development.
It is beyond the scope of this book to cover more than the basics of the Spring Framework configuration as is required by our project needs. However, we recommend that you browse through the detailed description of how the IoC container works at http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-definition to enhance their knowledge of the core principles.
This is the main configuration file used by Spring to configure and load the IoC bean container. The XML-based configuration has been the default way to configure Spring applications since the very start, but with Spring 3 Framework, it became possible to use the Java-based configuration. Both options achieve the same result—a fully configured Spring container. We will use the XML approach as it does not require any Java coding and is more intuitive and simple to use.
There have been many articles written over the years about the "complexities" of the Spring XML configuration. Prior to Java 1.5 and the introduction of annotations, there could have been a case made for such comments. Configuration files were lengthy and daunting for new users. This is no longer the case. Configuring a Spring container with XML is now a trivial process. Be wary of anyone who tells you otherwise!
The testingContext.xml
configuration file completely defines the Spring environment required for testing the DAO layer. The full file listing is:
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties" /> <bean id="tttDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/> <bean id="loadTimeWeaver" class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" /> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" p:showSql="true" p:databasePlatform="org.eclipse.persistence.platform.database.MySQLPlatform" /> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="tttDataSource" p:jpaVendorAdapter-ref="jpaVendorAdapter" p:persistenceXmlLocation="test-persistence.xml" /> <!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:dataSource-ref="tttDataSource" p:entityManagerFactory-ref="entityManagerFactory"/> <!-- checks for annotated configured beans --> <context:annotation-config/> <!-- Scan for Repository/Service annotations --> <context:component-scan base-package="com.gieman.tttracker.dao" /> <!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven /> </beans>
Let's look at each section in detail.
For those not familiar with XML, you can simply ignore the xmlns
definitions and schema location URLs. Consider them as "shortcuts" or "qualifiers" in the configuration file that provide the ability to validate the entries. Spring understands what <tx:annotation-driven />
means in the context of loading the Spring environment.
Each Spring application configuration file will have multiple namespace declarations depending on the resources your application needs. Defining the schema location in addition to the namespaces will allow NetBeans to provide helpful hints on configuration options:
The list of valid properties for different namespaces is very useful when new to Spring configuration.
The following bean loads the jdbc.properties
file and makes it available for use in the configuration file:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties" />
The ${}
syntax can then be used anywhere in the testingContext.xml
file to replace the token with the required jdbc
property.
DAO testing requires a connection to the MySQL database. The following Spring bean definition instantiates and makes available a fully configured DataSource:
<bean id="tttDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
The placeholders are automatically set with the properties loaded from the jdbc.properties
file:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/task_time_tracker jdbc.username=root jdbc.password=adminadmin
This very simple Spring configuration snippet replaces many lines of equivalent Java code if we had to implement the DataSource instantiation ourselves. Note how simple it would be to change any of the database properties for different testing scenarios, or for example, even change the database server from MySQL to Oracle. This flexibility makes the Spring IoC container very powerful for enterprise use.
You should note that the org.springframework.jdbc.datasource.DriverManagerDataSource
should only be used for testing purposes and is not for use in a production environment. The GlassFish server will provide a connection-pooled DataSource
for production use.
The loadTimeWeaver
and jpaVendorAdapter
bean definitions help configure the entityManagerFactory
bean that is used to load the persistence context. Note the way in which we identify the database platform (MySQL) and JPA implementation (EclipseLink) by using specific Spring bean classes:
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" p:showSql="true" p:databasePlatform="org.eclipse.persistence.platform.database.MySQLPlatform" />
Spring provides a large number of database and JPA implementations as can be seen when using autocomplete in NetBeans (the Ctrl + Space bar combination in NetBeans triggers the autocomplete options):
Helper beans are used to define implementation-specific properties. It is very easy to swap implementation strategies for different enterprise environments. For example, developers may use MySQL databases running locally on their own environment for development purposes. Production enterprise servers may use an Oracle database running on a different physical server. Only very minor changes are required to the Spring XML configuration file to implement such differences for the application environment.
This Spring bean defines the EntityManagerFactory
class that is used to create and inject the EntityManager
instance into the GenericDaoImpl
class:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="tttDataSource" p:jpaVendorAdapter-ref="jpaVendorAdapter" p:persistenceXmlLocation="test-persistence.xml" />
This definition references the tttDataSource
and jpaVendorAdapter
beans that are already configured, as well as the test-persistence.xml
persistence context definition file. Once again, Spring does a lot of work in the background by creating and configuring the EntityManager
instance and making it available for use in our code.
The Spring bean used to manage transactions is defined as follows:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:dataSource-ref="tttDataSource" p:entityManagerFactory-ref="entityManagerFactory"/>
This bean wires together the tttDataSource
and entityManagerFactory
instance to enable transactional behavior in our application. This behavior is applied to all classes with @Transactional
annotations; in our current situation this applies to all the DAO objects. Spring scans for this annotation and applies a transactional wrapper to each annotated method when the following line is included in the configuration file:
<tx:annotation-driven />
Which classes are scanned for the @Transactional
annotation? The following line defines that Spring should scan the com.gieman.tttracker.dao
package:
<context:component-scan base-package="com.gieman.tttracker.dao"/>
Autowiring is a Spring term used to automatically inject a resource into a managed bean. The following line enables autowiring in beans that have the @Autowired
annotation:
<context:annotation-config/>
We do not have any autowired annotations as of yet in our code; the next section will introduce how this annotation is used.
The Spring configuration file, when loaded by the Spring container, will do an enormous amount of work in the background configuring and wiring together the many supporting classes required by our application. The tedious and often error-prone "plumbing" code is done for us. Never again will we need to commit a transaction, open a database connection, or close a JDBC resource. These low-level operations will be handled very elegantly for us by the Spring Framework.
The Maven build process includes the ability to execute test suites. We will now need to add this functionality to the pom.xml
file. The required changes to the existing file are highlighted in the following code snippet:
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gieman</groupId> <artifactId>task-time-tracker</artifactId> <version>1.0</version> <packaging>war</packaging> <name>task-time-tracker</name> <properties> <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>3.2.4.RELEASE</spring.version> <logback.version>1.0.13</logback.version> </properties> <dependencies> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>javax.persistence</artifactId> <version>2.1.0-SNAPSHOT</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.5.0-SNAPSHOT</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId> <version>2.5.0-SNAPSHOT</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.26</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> <compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <warName>${project.build.finalName}</warName> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-endorsed</id> <phase>validate</phase> <goals> <goal>copy</goal> </goals> <configuration> <outputDirectory>${endorsed.dir}</outputDirectory> <silent>true</silent> <artifactItems> <artifactItem> <groupId>javax</groupId> <artifactId>javaee-endorsed-api</artifactId> <version>7.0</version> <type>jar</type> </artifactItem> </artifactItems> </configuration> </execution> <execution> <id>copy-all-dependencies</id> <phase>compile</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> <includeScope>compile</includeScope> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.14.1</version> <configuration> <skipTests>false</skipTests> <includes> <include>**/dao/*Test.java</include> </includes> <argLine>-javaagent:target/lib/spring-instrument-${spring.version}.jar</argLine> </configuration> </plugin> </plugins> </build> <repositories> <repository> <url>http://download.eclipse.org/rt/eclipselink/maven.repo/</url> <id>eclipselink</id> <layout>default</layout> <name>Repository for library EclipseLink (JPA 2.1)</name> </repository> </repositories> </project>
The first two changes add the mysql-connector-java
and junit
dependencies. Without these we will not be able to connect to the database or write test cases. These dependencies will download the appropriate Java libraries for inclusion into our project.
The most important settings are in the Maven plugin that performs the actual work. Adding the maven-surefire-plugin
will allow the test case execution based on the contents of the main/src/test
directory structure. This clearly separates the testing classes from our application classes. The main configuration properties for this plugin are:
<skipTests>
: This property can be true
(to disable testing) or false
(to enable testing).<includes>
: This property includes a list of file sets during testing. The setting <include>**/dao/*Test.java</include>
specifies that all the classes in any dao
subdirectory with the filename ending in Test.java
should be loaded and included in the testing process. You may specify any number of file sets.<argLine>-javaagent:target/lib/spring-instrument-${spring.version}.jar</argLine>
: This property is used to configure the Java Agent for the testing JVM and is required by Spring for the load-time weaving of classes, a discussion of which is beyond the scope of this text.Now that we have configured the Spring and Maven testing environments, we can start writing test cases.
3.144.114.85