第二十五部分_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。
相關文章
相關標籤/搜索