第二十五部分_Struts2.1与Spring整合

依赖注入以后、对象销毁以前自动调用方法:前端

经过相似于以前Spring项目编码的方式,咱们能够经过在setXXX()方法中输出相关的语句来获悉依赖关系注入的执行时机,经过下面介绍的方法能够在依赖关系注入完成以后自动执行一些方法。java

若是咱们想让一个类的实例在全部属性都已经设置好以后,就让它自动执行某些方法,有两种方式:web

  • 实现InitializingBean接口,而且实现里面的惟一方法afterPropertiesSet(),这个方法就会在全部的属性注入完以后自动的获得调用。
  • 在该类中定义一个任意名称的方法(好比init()),在applicationContext.xml中对应类的bean标签中添加init-method="init"。(前面指定的init名称)

Spring官方文档推荐使用后者,能够作到尽可能使得自定义类不与Spring发生关系(耦合),由于Spring倡导的原则是:尽可能减小接口之间的耦合性,Spring号称是非侵入性的,即便得整个程序根本感受不到Spring的存在,只须要把相关的信息都配置到配置文件里,Spring就能把原本一个一个独立的bean拼装成一系列互相关联的对象。spring

有初始化就有销毁,实现DisposableBean接口中的惟一抽象方法destroy()或者配置destroy-method属性,能够在对象销毁以前获得自动调用。apache

对于Spring的bean工厂(IoC)这块暂时先告一段落。后端

下面咱们看下一如何将前端框架Struts和一站式框架Spring(自己提供了对MVC的支持,Spring MVC,之因此不讲这个是由于它在国外用的不少,可是在国内用的比较少)有机的整合起来。tomcat

首先新建一个Web Project,命名为strutsspring。前端框架

1.首先完成struts相关的配置,拷贝以前项目的struts.xml至src目录下。服务器

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
	
	<struts>
		
		<package name="strutsspring" extends="struts-default">



		</package>

	</struts>

2.拷贝struts依赖的六个jar文件再加上io的jar包共七个jar文件至WEB-INF的lib目录下。session

3.在web.xml中进行相关配置,使之支持struts(也增长了对Spring的支持,后文介绍)。

<?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">
  
  <filter>
  	<filter-name>struts2</filter-name>
  	<filter-class>
  		org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  	</filter-class>
  </filter>
  
  <filter-mapping>
  	<filter-name>struts2</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <listener>
  	<listener-class>
  		org.springframework.web.context.ContextLoaderListener
  	</listener-class>
  </listener>
  
</web-app>

4.作完以上步骤,如今的工程就是一个典型的struts的工程。接下来把其Contextpath配置到tomcat(server.xml)中。

<Context path="/strutsspring" docBase="D:\JavaWeb\strutsspring\WebRoot" reloadable="true"/>

启动服务器,访问localhost:8080/strutsspring,页面弹出This is my JSP page.即为成功。

下面引入对Spring的支持,因为如今是一个web项目,比之之前普通的Java Application引入的包则多一些。

选中项目,MyEclipse->Add Spring Capabilities,选择Spring version 为Spring 2.5,jar包选择Spring 2.5 AOP Libraries、Spring 2.5 Core Libraries、Spring 2.5 Web Libraries,JAR Library Installation 选择Copy checked Library contents to project folder,点击Next,去掉Enable AOP Builder前面的勾勾,而后在Folder中将src改成WebRoot/WEB-INF,点击Finish。

到此为止,Struts和Spring都归入到项目中了,下面要作的就是将两者粘合起来,有两个步骤:

  • 将Struts的Spring插件也增长到WEB-INF的lib目录下。在官网下载的struts2.1.6下的lib目录下有一个struts2-spring-plugin-2.1.6.jar。这样Action的建立、销毁等工做都由Spring代为管理,Struts就放手无论了。这是为何呢?来到struts2-core-2.1.6.jar下面,里面有一个org.apache.struts2,其下有一个default.properties:在36-39行处有被注释掉的文字:
### if specified, the default object factory can be overridden here
### Note: short-hand notation is supported in some cases, such as "spring"
###       Alternatively, you can provide a com.opensymphony.xwork2.ObjectFactory subclass name here
# struts.objectFactory = spring

   而在struts-spring-plugin-2.1.6.jar中有一个struts-plugin.xml,有一个地方将Spring的object factory给启用了:

<!--  Make the Spring object factory the automatic default -->
    <constant name="struts.objectFactory" value="spring" />
  • 在web.xml中增长一个Spring的启动类(之前的版本经过一个filter启动,后续版本中经过一个listener启动:服务器一启动,listener的Class被实例化)
      <listener>
      	<listener-class>
      		org.springframework.web.context.ContextLoaderListener
      	</listener-class>
      </listener>

到如今,前期的配置上的整合工做才算结束。

重启服务器,能够看到输出中有一行信息:

信息: Initializing Spring root WebApplicationContext

查看Spring的API文档,可知WebApplicationContext实现了BeanFactory接口。


下面,咱们整合这两个框架,看看中间的流程是如何进行的。

新建login.jsp(引入Struts标签库<%@ taglib uri="/struts-tags" prefix="s" %>):

<body>
  	<s:form action="login">
  		<s:textfield name="username" size="20" label="username"></s:textfield>
  		<s:textfield name="password" size="20" label="password"></s:textfield>
  		
  		<s:submit value="submit"></s:submit>
  	</s:form>
  </body>

而后新建包com.test.action,在其下新建类LoginAction(增长了服务接口):

package com.test.action;

import com.opensymphony.xwork2.ActionSupport;
import com.test.service.LoginService;
import com.test.service.impl.LoginServiceImpl;

public class LoginAction extends ActionSupport
{
	private String username;
	
	private String password;
	
	private LoginService loginService;

	public LoginService getLoginService()
	{
		return loginService;
	}

	public void setLoginService(LoginService loginService)
	{
		this.loginService = loginService;
	}

	public String getUsername()
	{
		return username;
	}

	public void setUsername(String username)
	{
		this.username = username;
	}

	public String getPassword()
	{
		return password;
	}

	public void setPassword(String password)
	{
		this.password = password;
	}
	
	@Override
	public String execute() throws Exception
	{
		// 注意:业务逻辑永远不要写在Action里,在Action中应当只是完成数据校验、类型转换这样一些前期的处理工做。前期处理获得合法数据以后,才进入后端的业务逻辑层。
		
		// 若是没有Spring能够考虑这样写(缺点:接口和实现耦合在一块了):
		// loginService = new LoginServiceImpl();
		// loginService.isLogin(username, password);
		
		if(loginService.isLogin(username, password))
		{
			return SUCCESS;
		}
		else 
		{
			return ERROR;
		}
	}
}

业务逻辑的处理——新建包com.test.service,在下面新建接口LoginService:

package com.test.service;

public interface LoginService
{
	public boolean isLogin(String username, String password);
}

新建com.test.service.impl包,对service接口的实现类写在里面LoginServiceImpl(完成真正的业务处理):

package com.test.service.impl;

import com.test.service.LoginService;

/**
 * 该类完成真正的业务处理
 * @author asus
 *
 */
public class LoginServiceImpl implements LoginService
{
	public boolean isLogin(String username, String password)
	{
		if("hello".equals(username) && "world".equals(password))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

实现类定义完了,最终确定是供Action调用的,如何让Action知道是Spring帮咱们作的这件事?

  • 在LoginAction中声明它所须要的服务接口是什么。
  • 而后在struts.xml中配置(注意action中的class属性再也不是com.test.action.LoginAction):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
	
	<struts>
		
		<package name="strutsspring" extends="struts-default">

			
		<!-- loginAction是Spring的applicationContext.xml中bean的id中声明的一个名字 -->
			<action name="login" class="loginAction"> 
				<result name="success">/success.jsp</result>
				<result name="error">/error.jsp</result>
			</action>

		</package>

	</struts>

在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-2.5.xsd">

	<bean id="loginService" class="com.test.service.impl.LoginServiceImpl"></bean>
	<bean id="loginAction" class="com.test.action.LoginAction">
		<property name="loginService" ref="loginService"></property>
	</bean>
</beans>

LoginAction中的execute方法:

	@Override
	public String execute() throws Exception
	{
		// 注意:业务逻辑永远不要写在Action里,在Action中应当只是完成数据校验、类型转换这样一些前期的处理工做。前期处理获得合法数据以后,才进入后端的业务逻辑层。
		
		// 若是没有Spring能够考虑这样写(缺点:接口和实现耦合在一块了):
		// loginService = new LoginServiceImpl();
		// loginService.isLogin(username, password);
		
		if(loginService.isLogin(username, password))
		{
			return SUCCESS;
		}
		else 
		{
			return ERROR;
		}
	}

补充success.jsp(引入标签库)和error.jsp:

  <body>
    username:<s:property value="username"/><br/>
    password:<s:property value="password"/>
  </body>

error.jsp:

  <body>
    login error!!!
  </body>

重启服务,测试输入hello world显示success.jsp页面对应的信息,不然输出错误信息login error!!!

补充说明:

因为LoginServiceImpl是无状态的类,没有属性,只有方法,new多少次都没有变化,所以须要在applicationContext.xml的bean中增长一个scope属性(注意:对于action来讲,必定要将其配置成prototype或是request):

	<bean id="loginService" class="com.test.service.impl.LoginServiceImpl" scope="singleton"></bean>
	<bean id="loginAction" class="com.test.action.LoginAction" scope="prototype">

此外若是不配置scope,其默认值为singleton,所以配置scope除了影响效率,还影响程序的正确性。

对于Spring的配置文件的bean元素,其scope属性有以下几个值:

  1. singleton,单例。
  2. prototype,表示每次从容器中取出bean时,都会生成一个新实例。至关于new出来一个对象。
  3. request,该属性是基于web的,表示每次接受一个请求时,都会生成一个新实例。在这种状况下,request与prototype同样。
  4. session,表示每一个session中该对象只有一个。
  5. globalSession。
相关文章
相关标签/搜索