01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 1 1 TE RI AL Jump Star t Spring 2 MA It is always an exciting time when you first start to use a new software framework. Spring 2, indeed, is an exciting software framework in its own right. However, it is also a fairly large framework.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 2 Chapter 1: Jump Start Spring 2 All About Spring Spring started its life as a body of sample code that Rod Johnson featured in his 2002 Wrox Press book Expert One on One Java J2EE Design and Development (ISBN: 1861007841). The book was published during the height of J2EE popularity. Back in those days, the conventionally accepted way to create a serious enterprise Java application was to use Java 2 Enterprise Edition 1.3/1.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 3 Chapter 1: Jump Start Spring 2 wired components can be Java objects that you have written for the application, or one of the many prefabricated components in the Spring API library (or a component from a third-party vendor, such as a transaction manager from Hibernate). It is of paramount importance, then, to understand how components instantiation and wiring work in Spring.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 4 Chapter 1: Jump Start Spring 2 mathematic operation, and from the writer’s destination, by means of Java interfaces. Two interfaces are defined. The first, called Operation, encapsulates the mathematic operation: package com.wrox.begspring; public interface Operation { long operate(long op1, long op2); String getOpsName(); } Decoupling at the Interface Next, a component that performs addition can be written as the OpAdd class: package com.wrox.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 5 Chapter 1: Jump Start Spring 2 void showResult(String result) ; } One implementation of ResultWriter, called ScreenWriter, writes to the console screen: package com.wrox.begspring; public class ScreenWriter implements ResultWriter{ public ScreenWriter() {} public void showResult(String result) { System.out.println(result); } } Another implementation of ResultWriter, called DataFileWriter, writes the result to a file: package com.wrox.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 6 Chapter 1: Jump Start Spring 2 private Operation ops = new OpAdd(); private ResultWriter wtr = new ScreenWriter(); public static void main(String[] args) { CalculateScreen calc = new CalculateScreen(); calc.execute(args); } public void execute(String [] args) { long op1 = Long.parseLong(args[0]); long op2 = Long.parseLong(args[1]); wtr.showResult(“The result of “ + op1 + ops.getOpsName() + op2 + “ is “ + ops.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 7 Chapter 1: Jump Start Spring 2 Try It Out Creating a Modularized Application You can obtain the source code for this example from the Wrox download website (wrox.com). You can find the directory under src/chapter1/monolithic. The following steps enable you to compile and run first the monolithic version of the Calculate application, and then a version that is fully modularized. 1.
01612c01.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 9 Chapter 1: Jump Start Spring 2 beans.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 10 Chapter 1: Jump Start Spring 2 1. Change the directory to the source directory, and then compile the code using Maven 2: cd src\chapter1\springfirst mvn compile This may take a little while, since Maven 2 will download all the Spring libraries that you need from the global repository. Once the libraries are downloaded, Maven 2 keeps them in your local repository on your computer’s hard disk, and you will not have to wait for them again. 2.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 11 Chapter 1: Jump Start Spring 2 BeanFactory factory = (BeanFactory) context; CalculateSpring calc = (CalculateSpring) factory.getBean(“opsbean”); calc.execute(args); } public void execute(String [] args) { long op1 = Long.parseLong(args[0]); long op2 = Long.parseLong(args[1]); wtr.showResult(“The result of “ + op1 + ops.getOpsName() + op2 + “ is “ + ops.operate(op1, op2) + “!”); } } The preceding highlighted code creates an ApplicationContext.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 12 Chapter 1: Jump Start Spring 2 Note the XML schema and namespaces used in the document element. These are standard for Spring 2.0 and the schema defines the tags allowed within the descriptor. You are likely to find these schema in every Spring context descriptor file, except for some pre-2.0 legacy DTD-based descriptor files. (See the sidebar Support of Legacy DTD-Based Spring Wiring Syntax.)
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 13 Chapter 1: Jump Start Spring 2 2. 3. 4. 5. 6.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 14 Chapter 1: Jump Start Spring 2 log4j.rootLogger=FATAL, first log4j.appender.first=org.apache.log4j.ConsoleAppender log4j.appender.first.layout=org.apache.log4j.PatternLayout log4j.appender.first.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n Wiring Beans Automatically by Type In the preceding example you wired the properties of the CalculateSpring bean explicitly.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 15 Chapter 1: Jump Start Spring 2 3. 4. Change the directory back to the /springfirst directory in which pom.xml is located. Now, run the application using Maven 2 with the following command line: mvn exec:java -Dexec.mainClass=com.wrox.begspring.CalculateSpring –Dexec.args=”3000 3” First, note that you do not need to recompile at all; you perform this reconfiguration purely by editing an XML file — the context descriptor.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 16 Chapter 1: Jump Start Spring 2 Value of autowire Attribute Description byType The container examines the argument type of the setter methods on the bean, and tries to locate a bean with the same type. An error is raised when more than one bean with the same type exists, or when there is no bean of the required type.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 17 Chapter 1: Jump Start Spring 2 2. 3. Uses it to look up a resource bound at jdbc/WroxJDBCDS Casts the returned resource to a DataSource When writing your software components to be wired by Spring, however, you do not need to perform the lookup; you just start to use the DataSource. Consider this segment of code from a Spring component: private DataSource ds; public void setDs(DataSource datasource) { ds = datasource; } ... Connection conn = ds.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 18 Chapter 1: Jump Start Spring 2 the required resource and then injects it into the component, effectively inverting the control over the selection of the resource from the component to the container. IoC Container Container OpMultiply ScreenWriter OpMultiply ScreenWriter 1. Injects OpMultiply for ops property 1. Give me OpMultiply 2. Here is OpMultiply 2. Injects ScreenWriter for writer property 3. Give me ScreenWriter 4.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 19 Chapter 1: Jump Start Spring 2 3. Now, modify beans.xml to use the OpMultiply implementation instead: edit the file to match the highlighted lines shown here:
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 20 Chapter 1: Jump Start Spring 2 When the CalculateSpring bean is wired in beans.xml, the setter dependency injection is used to wire an implementation of OpMultiply, instead of the former OpAdd, to this ops property. This setter injection is highlighted in the following code:
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 21 Chapter 1: Jump Start Spring 2 SPRING AOP Existing target code modules Matches pointouts and apply aspects Apply aspect here Matched JoinPoint Logging aspect (code) Apply aspect here Apply aspect here Matched JoinPoint Matched JoinPoint Figure 1-4 Adding a Logging Aspect In this section, you can try out Spring AOP support by applying a logging aspect to the existing calculation code. The code for the logging aspect is the com.wrox.begspring,aspects.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 22 Chapter 1: Jump Start Spring 2 This code prints a logging message, similar to the following, whenever a method on the Operation interface (from the CalculateSpring code) is called: AOP logging -> execution(getOpsName) Try It Out Experimenting with Spring AOP Support Once you have created an aspect, in this case a logging aspect, you can apply it to a target (in this case the CalculateSpring components) through the context descriptor.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 23 Chapter 1: Jump Start Spring 2 public void setOps(Operation ops) { this.ops = ops; } public void setWriter(ResultWriter writer) { wtr = writer; } public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( “beans.xml”); BeanFactory factory = (BeanFactory) context; CalculateSpringAOP calc = (CalculateSpringAOP) factory.getBean(“opsbean”); calc.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 24 Chapter 1: Jump Start Spring 2
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 25 Chapter 1: Jump Start Spring 2 The argument to the logMethodExecution() method is a join point. This is a context object that marks the application point of the aspect. There are several methods on this join point that can be very useful in the aspect implementation. The following table describes some of the methods available at the join point.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 26 Chapter 1: Jump Start Spring 2 They decouple dependency specifications from business logic, and separate crosscutting concerns. All these things are desirable in software projects of any type and/or size. The Spring framework provides generic plumbing for creating modularized applications of any kind; you are not restricted to creating web-based enterprise Java applications. Going beyond the generic plumbing discussed so far, Spring offers much, much more.
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 27 Chapter 1: Jump Start Spring 2 Spring 2 API Modules Description AOP Supports AOP for application crosscutting concerns such as security, transactions, and other behaviors. Includes proxy-based implementations via Spring AOP, and integration with the AspectJ AOP language. DAO Provides a generic Data Access Objects abstraction over access of relational data from a variety of sources (such as JDBC).
01612c01.qxd:WroxPro 10/31/07 10:42 AM Page 28 Chapter 1: Jump Start Spring 2 Inversion of control (IoC) is used throughout Spring applications to decouple dependencies that typically block reuse and increase complexity in J2EE environments. Instead of a component manually looking up the provider of a service, the provider is injected into the component by the Spring container at runtime. This enables you to write reusable components that are independent of provider-specific features.