spring getstart
本文通过一个实例讲解spring开发过程中的一些特性。
1.通过一个refactoring的过程来体会使用spring的组件化和依赖注入的特性。
2.一个简单的web mvc demo。
1.问题是从hello world开始的。
一个简单的hello world程序:
/**
*
*/
/**
* 这是一个最简单的设计,但是在这个程序中这个类的职责
* 比较复杂,在下面的重构的重构中,将这个类分解为:消息
* 的提供者和消息的显示者。
*
* @author jefferyxu
*
*/
public class HelloWorld {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Hello World!");
}
}
将上面的类重构成下面的两个类:
IMessageDisplayer:
public interface IMessageDisplayer {
public void display() throws Exception ;
public void setSupplier(IMessageSupplier supplier);
public IMessageSupplier getSupplier();
}
IMessageSupplier:
public interface IMessageSupplier {
public String getMessage() ;
}
MessageDisplayer:
/**
*
*/
/**
* @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:
public class MessageSupplier implements IMessageSupplier {
@Override
public String getMessage() {
// TODO Auto-generated method stub
return "Hello World !";
}
}
客户程序如下:
/**
*
*/
/**
*
* 现在将这个程序进行重构,将这个程序分解成一个消息的提供者和
* 消息的显示 者,并且将这个依赖关系进行解耦。现在的问题是 主程序
* 需要依赖于具体类的实现(主要问题是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方法来实现对象的产生。实现代码如下:
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 :
supplier.class=getstart.MessageSupplier
客户程序如下:
/**
* @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 :
<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>
客户端程序:
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;
}
}
继续重构 上面的程序,上面的程序现在存在的问题主要是下面的这句:
这句的主要问题是在代码中直接将两个类的依赖关系写入。改进的办法是使用spring的“依赖注入”机制。实现如下:
applicationContext.xml:
<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 :
<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 :
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 :
<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 :
<%
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。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?