spring getstart

本文通过一个实例讲解spring开发过程中的一些特性。

1.通过一个refactoring的过程来体会使用spring的组件化和依赖注入的特性。

2.一个简单的web mvc demo。

1.问题是从hello world开始的。

一个简单的hello world程序:

package getstart;
/**
 * 
 
*/
/**
 * 这是一个最简单的设计,但是在这个程序中这个类的职责
 * 比较复杂,在下面的重构的重构中,将这个类分解为:消息
 * 的提供者和消息的显示者。
 * 
 * 
@author jefferyxu
 *
 
*/
public class HelloWorld {
    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        
// TODO Auto-generated method stub
        System.out.println("Hello World!");
    }
}

 

将上面的类重构成下面的两个类:

IMessageDisplayer:

package getstart;
public  interface IMessageDisplayer  {
    
public void display() throws Exception ;
    
public void setSupplier(IMessageSupplier supplier);
    
public IMessageSupplier getSupplier();
}

 

IMessageSupplier:

package getstart;
public  interface IMessageSupplier  {
   
public String getMessage() ;
}

 

MessageDisplayer:

package getstart;
/**
 * 
 
*/
/**
 * 
@author jefferyxu
 *
 
*/
public class MessageDisplayer implements IMessageDisplayer {
    
private IMessageSupplier supplier;
    
    
/* (non-Javadoc)
     * @see IMessageDisplayer#display()
     
*/
    @Override
    
public void display() throws Exception {
        
if(supplier == null) {
            
throw new Exception("supplier must be set.");
        }
            
        System.out.println(supplier.getMessage());
    }
    
/**
     * 
@return the supplier
     
*/
    
public IMessageSupplier getSupplier() {
        
return supplier;
    }
    
/**
     * 
@param supplier the supplier to set
     
*/
    
public void setSupplier(IMessageSupplier supplier) {
        
this.supplier = supplier;
    }
    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        
// TODO Auto-generated method stub
    }
}

 

MessageSupplier:

package getstart;
public  class MessageSupplier  implements IMessageSupplier {
    @Override
    
public String getMessage() {
        
// TODO Auto-generated method stub
        return "Hello World !";
    }
 }

 

客户程序如下:

package getstart;
/**
 * 
 
*/
/**
 * 
 * 现在将这个程序进行重构,将这个程序分解成一个消息的提供者和
 * 消息的显示 者,并且将这个依赖关系进行解耦。现在的问题是 主程序
 * 需要依赖于具体类的实现(主要问题是new MessageSupplier()),下面
 * 对这个依赖解耦,具体的做法是将具体类的产生通过一个工厂的方法来 
 * 代替new的实现,同时工厂类在实现的时候通过java中的反射机制来实现
 * 根据配置文件来加载对应类 .
 * 
 * 
@author jefferyxu
 *
 
*/
public class HelloWorldBetter {
    
/**
     * 
@param args
     * 
@throws Exception 
     
*/
    
public static void main(String[] args) throws Exception {
        
// TODO Auto-generated method stub
        IMessageSupplier supplier = new MessageSupplier();
        
        IMessageDisplayer displayer 
= new MessageDisplayer();
        displayer.setSupplier(supplier);
        
        displayer.display();
    }
}

 

但是上面中依旧存在的问题是主程序需要依赖具体类的实现(主要问题是new MessageSupplier())。解耦的方法是使用一个factory方法来实现对象的产生。实现代码如下:

package getstart;
import java.io.FileInputStream;
import java.util.Properties;
import org.aspectj.apache.bcel.generic.ReturnaddressType;
import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;

/**
 * 
@author jefferyxu
 *
 
*/
public class MessageSupportFactory {
    
    
/**
     * 单件模式的全局变量
     
*/
    
private static MessageSupportFactory factory = null;
    
/**
     * private构造函数
     
*/
    
private MessageSupportFactory() {
        properties 
= new Properties();
        
        
try {
            properties.load(
new FileInputStream("src/msgbean.properties"));
        } 
catch (Exception e) {
            
// TODO: handle exception
            e.printStackTrace();
        }
    }
    
    
private Properties properties = null;
    
    
/**
     * 单件模式产生factory对象
     * 
@return
     
*/
    
public static MessageSupportFactory getInstance() {
        
if(factory == null) {
            
return new MessageSupportFactory();
        }
        
else {
            
return factory;
        }
    }
    
    
/**
     * 通过配置文件产生一个displayer的实例.
     * 
@return
     
*/
    
public MessageDisplayer makeDisplayer() {
        String displayerClass 
= properties.getProperty("displayer.class");
    
        
try {
            
return (MessageDisplayer) Class.forName(displayerClass).newInstance();
        } 
catch (Exception e) {
            
// TODO: handle exception
            e.printStackTrace();
        }
        
        
return null;
    }
    
    
public MessageSupplier makeSupplier() {
        String displayerClass 
= properties.getProperty("supplier.class");
        
        
try {
            
return (MessageSupplier)Class.forName(displayerClass).newInstance();
        } 
catch (Exception e) {
            
// TODO: handle exception
            e.printStackTrace();
        }
        
        
return null;
    }
}    

 

msgbean.properties :

displayer.class=getstart.MessageDisplayer
supplier.class=getstart.MessageSupplier

 

客户程序如下:

package getstart;
/**
 * 
@author jefferyxu
 *
 
*/
public class HelloWorldWidthFactory {
    
public static void main(String[] args) throws Exception {
        MessageSupplier supplier 
= 
            MessageSupportFactory.getInstance().makeSupplier();
        
        MessageDisplayer displayer 
= 
            MessageSupportFactory.getInstance().makeDisplayer();
        
        displayer.setSupplier(supplier);
        
        displayer.display();
    }
}

 

通过上面的几步重构的话,客户端的程序基本上和实现类实现了解耦。但是上面种存在的问题是实现起来较为的复杂,如果改用spring框架来实现,大大简化上面的步骤.

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:p
="http://www.springframework.org/schema/p"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    
<bean id="displayer" name="displayer" class="getstart.MessageDisplayer">
    
</bean>
    
    
        
<bean id="supplier" name="supplier" class="getstart.MessageSupplier">
        
</bean>
</beans>

 

客户端程序:

package getstart;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 
@author jefferyxu
 *
 
*/
public class HelloWorldWithSpringUsgae {
    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        
/**
         * 加载spring的运行环境
         
*/
        ApplicationContext context 
= 
            
new ClassPathXmlApplicationContext("applicationContext.xml");
        
        
/**
         * 使用bean工厂,产生具体类
         
*/
        MessageSupplier supplier 
= 
            (MessageSupplier)context.getBean(
"supplier");
        MessageDisplayer displayer 
= 
            (MessageDisplayer)context.getBean(
"displayer");
        
        
/**
         * 这里直接在代码中直接将两者的依赖关系写入,所以
         * 整段代码的可重用性不好。
         
*/
        displayer.setSupplier(supplier);
        
        
try {
            displayer.display();
        } 
catch (Exception e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    
private static BeanFactory getFactory()  {
        DefaultListableBeanFactory factory 
= 
            
new DefaultListableBeanFactory();
        
        PropertiesBeanDefinitionReader reader 
= 
            
new PropertiesBeanDefinitionReader(factory);
        
        Properties properties 
= new Properties();
        
        
try {
            properties.load(
new FileInputStream("src/msgbean.properties"));
            
        } 
catch (FileNotFoundException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (IOException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        reader.registerBeanDefinitions(properties);
        
        
return factory;
    }
}

 

继续重构 上面的程序,上面的程序现在存在的问题主要是下面的这句:

displayer.setSupplier(supplier);

 

这句的主要问题是在代码中直接将两个类的依赖关系写入。改进的办法是使用spring的“依赖注入”机制。实现如下:

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:p
="http://www.springframework.org/schema/p"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    
<bean id="displayer" name="displayer" class="getstart.MessageDisplayer">
    
<property name="supplier"><ref local="supplier"/></property>
    
</bean>
    
    
        
<bean id="supplier" name="supplier" class="getstart.MessageSupplier">
        
</bean>
</beans>

 

客户端程序:

/**
 * 
 
*/
package getstart;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 
@author jefferyxu
 *
 
*/
public class HelloWorldWithSpringDIUsgae {
    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        
/**
         * 加载spring的运行环境
         
*/
        ApplicationContext context 
= 
            
new ClassPathXmlApplicationContext("applicationContext.xml");
        
        
/**
         * 使用bean工厂,产生具体类
         
*/
        MessageSupplier supplier 
= 
            (MessageSupplier)context.getBean(
"supplier");
        MessageDisplayer displayer 
= 
            (MessageDisplayer)context.getBean(
"displayer");
        
        
/**
         * 这里直接在代码中直接将两者的依赖关系写入,所以
         * 整段代码的可重用性不好。
         
*/
        
// displayer.setSupplier(supplier);
        
        
try {
            displayer.display();
        } 
catch (Exception e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    
private static BeanFactory getFactory()  {
        DefaultListableBeanFactory factory 
= 
            
new DefaultListableBeanFactory();
        
        PropertiesBeanDefinitionReader reader 
= 
            
new PropertiesBeanDefinitionReader(factory);
        
        Properties properties 
= new Properties();
        
        
try {
            properties.load(
new FileInputStream("src/msgbean.properties"));
            
        } 
catch (FileNotFoundException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (IOException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        reader.registerBeanDefinitions(properties);
        
        
return factory;
    }
}

 

2. 一个简单spring web mvc demo。

网站的目录结构:


web.xml :

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 
 
<!-- 
     tomcat将符合url pattern的请求分发到这个dispatchter
     上,然后这个dispatchter会默认的寻找以这个servlet-name
     -servlet.xml命名的xml文件
  
-->
 
<servlet>
  
<servlet-name>helloworld</servlet-name>
  
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  
<load-on-startup>1</load-on-startup>
 
</servlet>
 
<servlet-mapping>
  
<servlet-name>helloworld</servlet-name>
  
<url-pattern>/helloworld/*</url-pattern>
 
</servlet-mapping>
 
<welcome-file-list>
  
<welcome-file>index.jsp</welcome-file>
 
</welcome-file-list>
 
<login-config>
  
<auth-method>BASIC</auth-method>
 
</login-config>
</web-app>

 

HelloWorldController.java :

package getstart.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
 * 
@author jefferyxu
 *
 
*/
public class HelloWorldController implements Controller {
    
public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) 
throws Exception {
        
// TODO Auto-generated method stub
        
        
return new ModelAndView("/test.jsp");
    }
}

 

helloworld-servlet.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"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
<!--
        这个文件是在web.xml配置文件的helloworld/的子路径
        中定义的环境变量.按照下面的定义的话,将/test的路径 
        请求,转发到getstart.web.HelloWorldController上。
     
-->
    
<bean name="/test" class="getstart.web.HelloWorldController">
    
</bean>
    
</beans>

 

test.jsp :

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  
<head>
    
<base href="<%=basePath%>">
    
    
<title>My JSP 'test.jsp' starting page</title>
    
    
<meta http-equiv="pragma" content="no-cache">
    
<meta http-equiv="cache-control" content="no-cache">
    
<meta http-equiv="expires" content="0">    
    
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    
<meta http-equiv="description" content="This is my page">
  
</head>
  
  
<body>
   test.jsp from the HelloWorldController
  
</body>
</html>

 

可以使用下面的连接来访问:http://xuqiang-pc:8080/spring/helloworld/test。

posted @ 2010-10-13 15:46  qiang.xu  阅读(361)  评论(0编辑  收藏  举报