spring - users.csc.calpoly.eduusers.csc.calpoly.edu/~djanzen/courses/509s09/spring.pdf ·...
TRANSCRIPT
-
Copyright ©2009 David S. Janzen
Spring Tutorial
David Janzen
4/24/09
-
Copyright ©2009 David S. Janzen
Spring Motivation• Problems:
• Web and GUI applications are traditionally hard to test
• Screen-scraping is difficult
• Decoupling testable code from view and flow code
is difficult
• Web applications contain a lot of “plumbing” or
“glue” code
• Servlet controllers
• Configuration
• JNDI lookups
• Persistence mechanisms
-
Copyright ©2009 David S. Janzen
Spring Background
• Opportunities:
• We’ve learned a lot about improving design in the
last ten years
• UML
• Design Patterns
• Frameworks
• Plethora of good code available for reuse
• Open-Source projects
• COTS
-
Copyright ©2009 David S. Janzen
Your Code
Spring Overview• Spring is a lightweight framework for building Java
applications (Spring Home: http://www.springsource.org/)
• Any application (web, GUI, …)
• Lightweight means minimal impact to your code
• Spring is based on the principle of Inversion of Control
• Rather than class A declaring an instance of class B,
…
Class A
Class B
-
Copyright ©2009 David S. Janzen
Your Code
Spring
Spring Overview• Spring is a lightweight framework for building Java
applications
• Any application (web, GUI, …)
• Lightweight means minimal impact to your code
• Spring is based on the principle of Inversion of Control
• Rather than class A declaring an instance of class B,
some external process provides A with B
Class A
Class B
Interface I
Container
-
Copyright ©2009 David S. Janzen
Spring Overview• Dependency Injection is the run-time injecting of
dependencies
Your Code
SpringClass A
Class B
Interface I
Container
dependency
-
Copyright ©2009 David S. Janzen
POJO: Plain Old Java Objectpublic class Person {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Your Code
Class A
Person
Interface I
-
Copyright ©2009 David S. Janzen
Another POJOpublic class Book {
private int isbn;
private String title;
private Person author;
public void setIsbn(int i) {
isbn = i;
}
public void setTitle(String t) {
title = t;
}
public void setAuthor(Person a) {
author = a;
}
public Person getAuthor() {
return author;
}
…
}
Your Code
Book
Person
Interface I
-
Copyright ©2009 David S. Janzen
Typical Clientpublic class Client {
public static void main(String [] args) {
Person p = new Person();
Book b = new Book();
p.setFirstName(“David”);
p.setLastName(“Janzen”);
b.setIsbn(123456789);
b.setTitle(“TDD for Dummies by Dummies”);
b.setAuthor(p);
}
…
}
-
Copyright ©2009 David S. Janzen
Dependency Injection with Spring
• Spring provides a container that will
• Construct objects
• Populate object fields
• Inject references between objects
• You wire the objects together through a configuration
file such as xml
-
Copyright ©2009 David S. Janzen
Setter Injection• Declaration of a bean instantiates an object
• Values can be injected into the object
-
Copyright ©2009 David S. Janzen
Injecting Other Beans
123456789
TDD for Dummies by Dummies
-
Copyright ©2009 David S. Janzen
Constructor Injection• Constructor-arg tag is used to pass dependency via
constructor
David Janzen
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
-
Copyright ©2009 David S. Janzen
Multi-Type Constructor Injection• What if two constructors have an argument of
different types?
• Constructor-arg tag can specify a type
24
public class Person {
private String name; private int age;
public Person(String name) { this.name = name; }
public Person(int age) { this.age = age; }
}
Invokes String constructor
24
-
Copyright ©2009 David S. Janzen
Multi-Arg Constructor Injection• We can specify the order of constructor arguments
with index
David
Janzen
public class Person {
private String firstName, lastName;
public Person(String fname, String lname) {
this.firstName = fname;
this.lastName = lname;
}
}
-
Copyright ©2009 David S. Janzen
Wiring beans in XML
� Root element is
� Contains one or more elements
� Beans can be named by▪ id
▪ name (used as name if no id given)
▪ class (fully-qualified classname used as name if no id or name given)
Preferred because XML editors can verify this
-
Copyright ©2009 David S. Janzen
Bean Name Aliasing
� Beans can have multiple names
▪ First is default
▪ Could aid in maintenance
▪ Ex. consolidate two classes into one
-
Copyright ©2009 David S. Janzen
Typical Spring Application
POJI/POJO
Spring BeanFactory
Bean Wiring
main() or Servlet
-
Copyright ©2009 David S. Janzen
Spring Overview• Spring acts more like a container than a framework
• Constructs instances of classes
• With desired dependencies (DI)
• Integrates with data access options
• JDBC or ORM (Hibernate, iBATIS, JDO)
• Transaction management
• Web MVC
• Aspect oriented programming
• Remoting
• E-Mail support
• Job scheduling support
-
Copyright ©2009 David S. Janzen
Spring Organization
Diagram from “Spring in Action” by Walls and Breidenbach
-
Copyright ©2009 David S. Janzen
Spring Packages
Spring’s MVC frameworkspring-webmvc.jar
Most of above w/o mocksspring.jar
Struts integration, file upload, …spring-web.jar
Extend dao for Hibernate, other ORMsspring-orm.jar
Mocks to aid in testingspring-mock.jar
Data access with JDBC, transactionsspring-dao.jar
Basic DI supportspring-core.jar
Extensions, remoting,…spring-context.jar
Aspect-oriented programmingspring-aop.jar
ContainsJar File
-
Copyright ©2009 David S. Janzen
Declarative vs. Programmatic• Most Spring facilities can be configured in either a
declarative or programmatic way
• Declarative generally means the configuration is defined
in a file (XML, properties, …)
• Programmatic generally means the configuration is
defined in software
• Declarative configuration allows you to make changes
to the system without recompiling
-
Copyright ©2009 David S. Janzen
Exercise Preparation• Examine BooksMap files
• Read TestBooksMap.java carefully
• Examine run.sh
• Run run.sh
• Examine testTitlesMapbean.xml
• Examine coverage.txt
-
Copyright ©2009 David S. Janzen
Exercise• Retrieve the BooksMap example from
http://users.csc.calpoly.edu/~djanzen/courses/509S09/BooksMap.tar
• Untar in a directory on vogon
tar xvf BookMaps.tar
• Ensure that all tests pass
• Add another test or two to TestBooksMap.java
• Create a new book and check that it exists
• Stretch: What happens if you ask for a book that is
not in the map?
• What is different about the third test
(testBookTitlesAutoWire)? Add a second Person in this
test. What happens?
-
Copyright ©2009 David S. Janzen
Singleton Bean Instantiation� By default, all beans are singletons
▪ So calling getBean() always returns the same one
public class TestPerson {
@Test public void testSingleton() {
try {
//write testSingletonbeans.xml
XmlBeanFactory factory =
new XmlBeanFactory(new FileSystemResource("testSingletonbeans.xml"));
Person p1 = (Person)factory.getBean("jd");
Person p2 = (Person)factory.getBean("jd");
assertEquals(p1.getFirstName(),"John");
assertEquals(p2.getFirstName(),"John");
assertTrue(p1 == p2);
assertTrue(p1.getFirstName().equals(p2.getFirstName()));
assertTrue(p1.getLastName().equals(p2.getLastName()));
John
Doe
-
Copyright ©2009 David S. Janzen
Non-Singleton Bean Instantiation� The instantiation mode can be changed
▪ Specify singleton=“false”
public class TestPerson {
@Test public void testNonSingleton () {
try {
//write testSingletonbeans.xml
XmlBeanFactory factory =
new XmlBeanFactory(new FileSystemResource("testSingletonbeans.xml"));
Person p1 = (Person)factory.getBean("jd");
Person p2 = (Person)factory.getBean("jd");
assertEquals(p1.getFirstName(),"John");
assertEquals(p2.getFirstName(),"John");
assertTrue(p1 != p2);
assertTrue(p1.getFirstName().equals(p2.getFirstName()));
assertTrue(p1.getLastName().equals(p2.getLastName()));
John
Doe
-
Copyright ©2009 David S. Janzen
ApplicationContext
� See JavaDocs for ApplicationContext
� Everything we know about BeanFactory we can apply to ApplicationContext
-
Copyright ©2009 David S. Janzen
Stand-alone ApplicationContext
POJI/POJO
ApplicationContext
Bean Wiring
client
-
Copyright ©2009 David S. Janzen
Web ApplicationContext
POJI/POJO
ApplicationContext
Bean Wiring
servlet
Automatically loaded
-
Copyright ©2009 David S. Janzen
Spring MVC Architecture
Dispatcher Servlet
Controller
View
Model
Based on http://www.springframework.org/docs/MVC-step-by-step/Spring-MVC-step-by-step.html by Thomas Risberg
See sample of files in WebMVC
-
Copyright ©2009 David S. Janzen
Configuring web.xml� war/WEB-INF/web.xml (applicationContext.xml)
springapp
org.springframework.web.servlet.DispatcherServlet
1
springapp
*.htm
index.jsp
Route all *.htm to this servlet
Identify a Spring DispatcherServlet
-
Copyright ©2009 David S. Janzen
Configuring DispatcherServlet
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xml
-
Copyright ©2009 David S. Janzen
Configuring springapp-servlet.xml� war/WEB-INF/springapp-servlet.xml
springappController
Map hello.htm to springappController
Identify a controller
-
Copyright ©2009 David S. Janzen
Configuring a Controller
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xmlspringapp-servlet.xml
-
Copyright ©2009 David S. Janzen
Configuring libraries
� Create a lib folder under war/WEB-INF
� Copy the follow jars from where you extracted
the Spring download to war/WEB-INF/lib
▪ spring.jar (from spring-framework-1.2.3/dist)
▪ commons-logging.jar (from spring-framework-
1.2.3/lib/jakarta-commons)
▪ log4j-1.2.9.jar (from spring-framework-1.2.3/lib/log4j)
-
Copyright ©2009 David S. Janzen
Creating the Controller� src/SpringappController.javaimport org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SpringappController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
return new ModelAndView("");
}
}
-
Copyright ©2009 David S. Janzen
Configuring a View
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xmlspringapp-servlet.xml
SpringappController.java
hello.htm
-
Copyright ©2009 David S. Janzen
Creating a View
� Create the file hello.jsp in war
� Include something like this in hello.jsp
My First Spring Application
My First Spring Application
Isn't this cool.
You entered hello.htm.
The DispatcherServlet noticed it was a *.htm request
(according to web.xml) ...
so it mapped the request to the SpringappController (as
defined in springapp-servlet.xml).
SpringappController logged what was happening then returned
the view "hello.jsp“ and voila, here we are!
-
Copyright ©2009 David S. Janzen
Set View in Controller� Modify SpringappController.java in src
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SpringappController implements Controller {
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
return new ModelAndView("hello.jsp");
}
}
-
Copyright ©2009 David S. Janzen
Configuring a View
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xmlspringapp-servlet.xml
SpringappController.java
hello.jsp
hello.htm
-
Copyright ©2009 David S. Janzen
Modify Modelpublic class SpringappController implements Controller {
private ProductManager prodMan;
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String now = (new java.util.Date()).toString();
Map myModel = new HashMap();
myModel.put("now", now);
myModel.put("products",
getProductManager().getProducts());
return new ModelAndView("hello", "model", myModel);
}
public void setProductManager(ProductManager pm){
prodMan = pm;
}
public ProductManager getProductManager() {
return prodMan;
}
-
Copyright ©2009 David S. Janzen
View can access Model
Products
$
Increase Prices
-
Copyright ©2009 David S. Janzen
Business Data in Model
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xmlspringapp-servlet.xml
SpringappController.java
hello.jsp
hello.htm
Product.javaProductManager.java
-
Copyright ©2009 David S. Janzen
Testing Controller and Model
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xmlspringapp-servlet.xml
SpringappController.java
hello.jsp
hello.htm
Product.javaProductManager.java
TestProductManager.java
TestSpringappController.java
springapp-servlet.xml
-
Copyright ©2009 David S. Janzen
Adding a Controller and Validator
Dispatcher Servlet
Controller
View
Model
build.xml build.properties
web.xmlspringapp-servlet.xml
SpringappController.java
hello.jsp
hello.htm
PriceIncreaseValidator.java
ProductManager.java
PriceIncreaseFormController.java
priceincrease.jsp
PriceIncrease.java
priceincrease.htm
messages.properties
-
Copyright ©2009 David S. Janzen
Spring Resources
� www.springsource.org
� Professional Java Development with the Spring Framework
� Spring in Action
� Pro Spring