springframework 2.5引入了完整的annotaion配置注解,使用這些annotation可以大量的減少bean的定義,也使得程序開發更簡單和容易維護。
當然你要使用annotation就需要使用java5以上版本。
使用annotaion定義一個bean
@Component是一個通用注解,用于說明一個類是一個spring容器管理的類。
除此之外,還有@Controller, @Service, @Repository是@Component的細化,這三個注解比@Component帶有更多的語義,它們分別對應了表現層、服務層、持久層的類。
如果你只是用它們定義bean,你可以僅使用@Component,但是既然spring提供這些細化的注解,那肯定有使用它們的好處,不過在以下的例子中體現不出。
定義了一個接口
package test1;
interface MovieFinder {
String getData();
}
定義一個實現
package test1;
import org.springframework.stereotype.Repository;
@Repository
public class JpaMovieFinder implements MovieFinder {
@Override
public String getData() {
return "This is JpaMovieFinder implementation!";
}
}
這里使用了注解@Repository,說明這是一個受spring容器管理的bean定義,這個注解沒有指定bean的名字,默認為小寫開頭的類名,就是jpaMovieFinder,如果你要指定名字,可以這樣寫@Repository("myMovieFinder")。
這里也可以使用@Component這個注解,在這里例子中體現不出用@Repository的好處。
這里沒有指定這個bean的scope,缺省是singleton,如果你要其他scope,可以使用注解@Scope
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
spring掃描并注冊注解的bean
JpaMovieFinder只是添加了一個注解,這并不會自動被注冊到spring容器中,我們需要告訴spring容器到那里去尋找這些bean。
配置如下:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="test1"/>
</beans>
<context:component-scan base-package="test1"/>這個配置告訴spring容器到test1這個package下去掃描所有的類,從而找到被注解的類。
由于并不是test1下的所有的類都有注解,全部遍歷效率不高,所以spring定義了過濾器用于減小掃描范圍,這里為了簡單起見沒有使用。
使用注解進行依賴注入
package test1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SimpleMovieLister {
@Autowired
private MovieFinder movieFinder;
public String getData(String name) {
return "Hi " + name + "! " + movieFinder.getData();
}
public MovieFinder getMovieFinder() {
return movieFinder;
}
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
SimpleMovieLister是一個服務類,它也使用了@Service注解為了bean,這個類用到了MovieFinder,為了注入這個類的實現,這里使用了注解@Autowired,spring容器會自動找到合適的bean注入進去。注意這里并沒有指定被注入bean的名字,因為spring根據只發現了一個實現,那就是jpaMovieFinder。后面,我們會看到有兩個實現會怎樣。
注意,上面代碼使用@Autowired時,public void setMovieFinder(MovieFinder movieFinder) 這個方法是不需要的,你可以把它刪除了試一試。如果你使用xml的配置方式,該方法必須存在。我這里保留該方法,是為了后面測試注解和xml配置混合使用的方式。
測試1
package test1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("test1/beans.xml");
SimpleMovieLister m = (SimpleMovieLister)context.getBean("simpleMovieLister");
System.out.println(m.getData("Arthur"));
}
}
控制臺上會打印 Hi Arthur! This is JpaMovieFinder implementation!
增加MovieFinder的第二個實現
package test1;
import org.springframework.stereotype.Repository;
@Repository
public class IbatisMovieFinder implements MovieFinder {
@Override
public String getData() {
return "This is IbatisMovieFinder implementation!";
}
}
這時運行Main,系統會報錯:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMovieLister': Injection of resource fields failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test1.MovieFinder] is defined: expected single matching bean but found 2: [jpaMovieFinder, ibatisMovieFinder]
從錯誤信息中我們可以看到現在MovieFinder有兩個bean實現了,一個是jpaMovieFinder,另一個是ibatisMovieFinder,spring容器不知道應該使用哪一個bean。這時可以使用注解@Qualifier指定具體的bean。
//...
@Service
public class SimpleMovieLister {
@Autowired
@Qualifier("ibatisMovieFinder")
private MovieFinder movieFinder;
//...
這里我們指定注入的是ibatisMovieFinder這個bean。
運行Main, 控制臺上會打印 Hi Arthur! This is IbatisMovieFinder implementation!
Java6提供的注入注解
spring也可以使用java6提供的@Resource注解來指定注入哪一個bean。
//...
@Service
public class SimpleMovieLister {
@Resource(name="ibatisMovieFinder")
private MovieFinder movieFinder;
//...
這和@Autowired功能是一致的。
使用注解還是xml
使用注解很方便,但從上面的例子我們也可以看出注解的問題,MovieFinder有兩個實現,SimpleMovieLister是在程序中用注解指定了使用哪一個實現,如果要修改,需要修改源程序。所以,注解只適用于固定依賴的情況。如果依賴需要在部署的時候做調整,那還是使用xml的配置方式方便,畢竟只需要修改一下xml文件即可。
實際使用時,我們可以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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="test1"/>
<bean id="simpleMovieLister1" class="test1.SimpleMovieLister">
<property name="movieFinder" ref="jpaMovieFinder" />
</bean>
</beans>
使用xml配置方式定義了另外一bean,注入了jpaMovieFinder這個實現。
package test1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("test1/beans.xml");
SimpleMovieLister m = (SimpleMovieLister)context.getBean("simpleMovieLister");
System.out.println(m.getData("Arthur"));
SimpleMovieLister m1 = (SimpleMovieLister)context.getBean("simpleMovieLister1");
System.out.println(m1.getData("Arthur"));
}
}
simpleMovieLister是從注解來的,simpleMovieLister1是從xml配置來的。運行結果:
Hi Arthur! This is IbatisMovieFinder implementation!
Hi Arthur! This is JpaMovieFinder implementation!
證明混合使用是可行的,你可以繼續測試,用xml重新配置simpleMovieLister。
因此,即使我一開始使用了注解,之后我后悔了,沒有關系,不用修改源程序,以前用xml怎么配置現在還是怎么配置。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/dqatsh/archive/2008/12/08/3478000.aspx
在一個稍大的項目中,通常會有上百個組件,如果這些組件采用xml的bean定義來配置,顯然會增加配置文件的體積,查找以及維護起來也不太方便。Spring2.5為我們引入了組件自動掃描機制,他可以在類路徑底下尋找標注了@Component,@Service,@Controller,@Repository注解的類,并把這些類納入進spring容器中管理。它的作用和在xml文件中使用bean節點配置組件時一樣的。要使用自動掃描機制,我們需要打開以下配置信息
3.完成對ContextLoaderListener的初始化以后, Tomcat開始初始化DispatchServlet,- 還記得我們在web.xml中隊載入次序進行了定義。DispatcherServlet會建立自己的ApplicationContext,同時建立這個自己的上下文的時候會從ServletContext中得到根上下文作為父上下文,然后再對自己的上下文進行初始化,并最后存到 ServletContext中去供以后檢索和使用。
可以從DispatchServlet的父類FrameworkServlet的代碼中看到大致的初始化過程,整個ApplicationContext的創建過程和ContextLoder創建的過程相類似:
一、 概述 <o:p></o:p>
二、 Spring 初始化之旅 <o:p></o:p>
a) Spring 初始化的時候首先要運行的類為: org.springframework.web.context. ContextLoaderListener 或 org.springframework.web.context. ContextLoaderServlet 。
它們在初始化函數里無一例外地實例化了 ContextLoader 類 , 然后調用了它的函數 public WebApplicationContext initWebApplicationContext(ServletContext ) 。
接下來看一下在這個方法里干了寫什么
b) 在他的方法體內,關鍵是“ this.context = createWebApplicationContext(servletContext, parent); ”新建了一個“ ConfigurableWebApplicationContext ”類型的對象,在這一步實例化中幾乎完成了所有的 spring 初始化工作。讀取了所有的 spring 配置文件。它的工作步驟如下所述。
c) 首先,在將“ ConfigurableWebApplicationContext ”類型的對象實例化以后(這個對象實際的類型是這個包內的 XmlWebApplicationContext ),然后又給這個實例設置了三個屬性,“ wac.setParent(parent); ”在默認的初始化過程中這一步設置了一個 null 值,然后又設置了一個“ wac.setServletContext(servletContext); ”,將系統默認的上下文設置進來,比較重要的是下面這一段:
if (configLocation != null) {
// 讀取 spring 的應用配置文件
wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,Configurabl eWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
它將我們的配置文件名放置到 wac 變量中,以待在后續的操作中使用。然后調用 “ wac.refresh(); ”完成主要的初始化 BeanFactory 的操作。如下。
d) 首先我們應該看一下我們實例化的對象
org.springframework.web.context.support.XmlWebApplicationContext 的類圖:
<o:p> </o:p>
e) “ wac.refresh(); ”從類結構里我們能找到這個方法來自它的父類: AbstractApplicationContext 在它的 refresh() 方法內我們可以看到 spring 的復雜邏輯。
首先執行了 refreshBeanFactory(); (來自 AbstractRefreshableApplicationContext )見 f),
f) refreshBeanFactory(); 這個方法由負責維護變量 beanFactory 的子類 AbstractRefreshableApplicationContext 實現,默認情況下這個方法直接實例化一個新的 DefaultListableBeanFactory 類型的 BeanFacorty, 然后調用一個起緩沖作用的配置函數生成一個將 beanFacroty 包裝起來的對象 beanDefinitionReader ,然后對這個對象進行屬性配置,實際上該方法主要負責生成一個臨時的操作對象,對應調用的函數為“ loadBeanDefinitions(beanFactory); ”該方法為初始化期間較為重要的一個。 該方法來自其子類: AbstractRefreshableWebApplicationContext 對應的函數:
protected void loadBeanDefinitions(DefaultListableBeanFactory) ,然后這里又調用了自己定義的 protected void loadBeanDefinitions(XmlBeanDefinitionReader) 方法。此時,它就使用到了在 c) 中設置了的( wac.setConfigLocations(……)) 我們開發中密切相關的配置文件。(同時也要記住此時這個函數的參數 beanDefinitionReader ,之前已經設置了“ beanDefinitionReader.setResourceLoader(this); ”這里的 this 是我們在前面見到的 XmlWebApplicationContext (一個定義好了的上下文))。接著往下:
“ reader.loadBeanDefinitions(configLocations[i]); ” reader 開始加載我們配置文件內的東西了,不過真正復雜的實現此時才開始,我們繼續往下走,在接下來的方法內默認情況下會執行:
if (resourceLoader instanceof ResourcePatternResolver) (該判斷條件為 true ) , 由于從上面我們知道: beanDefinitionReader.setResourceLoader(this); 而 this 的類型為: XmlWebApplicationContext 所以 ((ResourcePatternResolver) resourceLoader).getResources(location); 得到一個 Resource[] 數組,接下來調用:
int loadCount = loadBeanDefinitions(resources); 該函數繼續調用自己子類定義的一系列臨時接口最終執行到 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); 在這個函數內初始化了處理 xml 文件的一些對象并將用戶的配置文件解析為一個 Document 對象。然后又執行了一系列函數直到
return parser.registerBeanDefinitions(this, doc, resource); 這個函數來自我們新建的 DefaultXmlBeanDefinitionParser ,在這個類里最終執行了對 xml 文件的解析工作和對 beanFacroty 變量執行了設置工作。
g) 終于我們從這些繁雜的邏輯中跳了出來,繼續執行 AbstractApplicationContext.refresh() 下面的工作,后續的代碼主要仍舊是往一些常量里面設值。
此時 spring 初始化過程就結束了
評述:啟動過程如下:
1.創建一個ApplicationContext的實例ac
2.讀取配置文件,ac簡單的設置(比如有多少bean)
3.所有的beanfactory后處理開始以此執行
4.開始創建bean的實例
5.進行注入(如果有其他bean,迭代執行)
6.如何實現一些接口(BeanFactoryAware, BeanNameAware)以此該bean執行相應方法
7.所有的bean后處理開始執行,中間如果實現InitializingBean,該bean執行相應方法)
spring中提供 ContextLoaderListenter類,用來加載context的xml文件。 spring為struts提供ContextLoaderPlugIn類,此類也可以加載context的xml文件。 區別在于,兩種方式加載的WebApplicationContext,以不同的Key存放在ServletContext中。而如果你定義了HibernateFilter的話,spring會利用WebApplicationContextUtils來獲取WebApplicationContext,而此類并不識別ContextLoaderPlugIn類所加載的上下文,此時便會拋出異常: No WebApplicationContext found: no ContextLoaderListener registered? 利用ContextLoaderListenter來加載dao、service級別的context,而對于struts的action,用ContextLoaderPlugIn加載。 |
2. 依賴容器的參數化事務管理
通過容器提供的集約式參數化事務機制,實現事務的外部管理,如EJB 中的事務管理模式。
容器管理的參數化事務為程序開發提供了相當的靈活性,同時因為將事務委托給容器進行管理,
應用邏輯中無需再編寫事務代碼,大大節省了代碼量(特別是針對需要同時操作多個事務資源的應用),從而提高了生產率。
比如生產環境的jdbc.properties里定義了jdbc連接為Oracle,并通過PlaceholderConfigurer設置到<bean id="dataSource"> 里,在測試時再載入下面的applicationContex-test.xml文件,就能透明的將配置更改為嵌入式數據庫。
applicationContext-test.xml: 定義載入的properties。
<bean id="testPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> <property name="location" value="classpath:spring/test/jdbc.properties"/> </bean>
spring/test/jdbc.properties: 將ApplicationContext 中id為dataSource的bean的url屬性改為使用hsqldb。
你可以通過下列途徑學習spring:
(1) spring下載包中doc目錄下的MVC-step-by-step和sample目錄下的例子都是比較好的spring開發的例子。
(2) AppFuse集成了目前最流行的幾個開源輕量級框架或者工具Ant,XDoclet,Spring,Hibernate(iBATIS),JUnit,Cactus,StrutsTestCase,Canoo's WebTest,Struts Menu,Display Tag Library,OSCache,JSTL,Struts 。
你可以通過AppFuse源代碼來學習spring。
AppFuse網站:http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse
(3)Spring 開發指南(夏昕)(http://www.xiaxin.net/Spring_Dev_Guide.rar)
一本spring的入門書籍,里面介紹了反轉控制和依賴注射的概念,以及spring的bean管理,spring的MVC,spring和hibernte,iBatis的結合。
(4) spring學習的中文論壇
SpringFramework中文論壇(http://spring.jactiongroup.net)
Java視線論壇(http://forum.javaeye.com)的spring欄目
2、利用Spring框架編程,console打印出log4j:WARN Please initialize the log4j system properly?
說明你的log4j.properties沒有配置。請把log4j.properties放到工程的classpath中,eclipse的classpath為bin目錄,由于編譯后src目錄下的文件會拷貝到bin目錄下,所以你可以把log4j.properties放到src目錄下。
這里給出一個log4j.properties的例子:
log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p (%F:%L) - %m%n
3、出現 java.lang.NoClassDefFoundError?
一般情況下是由于你沒有把必要的jar包放到lib中。
比如你要采用spring和hibernate(帶事務支持的話),你除了spring.jar外還需要hibernat.jar、aopalliance.jar、cglig.jar、jakarta-commons下的幾個jar包。
http://www.springframework.org/download.html下載spring開發包,提供兩種zip包
建議你下載開發包。這個zip解壓縮后比后者多一個lib目錄,其中有hibernate、j2ee、dom4j、aopalliance、jakarta-commons等常用包。
4、java.io.FileNotFoundException: Could not open class path resource [....hbm.xml],提示找不到xml文件?
原因一般有兩個:
(1)該xml文件沒有在classpath中。
(2)applicationContext-hibernate.xml中的xml名字沒有帶包名。比如:
User.hbm.xml 錯,改為: com/yz/spring/domain/User.hbm.xml
net.sf.hibernate.dialect.MySQLDialect true
5、org.springframework.beans.NotWritablePropertyException: Invalid property 'postDao' of bean class?
出現異常的原因是在application-xxx.xml中property name的錯誤。 中name的名字是與bean的set方法相關的,而且要注意大小寫。
比如
public class PostManageImpl extends BaseManage implements PostManage {
private PostDAO dao = null;
public void setPostDAO(PostDAO postDAO){
this.dao = postDAO;
}
}
那么xml的定義應該是:
對 錯
6、Spring中如何實現事務管理?
首先,如果使用mysql,確定mysql為InnoDB類型。
事務管理的控制應該放到商業邏輯層。你可以寫個處理商業邏輯的JavaBean,在該JavaBean中調用DAO,然后把該Bean的方法納入spring的事務管理。
比如:xml文件定義如下:
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED
com.yz.spring.service.implement.UserManageImpl就是我們的實現商業邏輯的JavaBean。我們通過parent元素聲明其事務支持。
7、如何管理Spring框架下更多的JavaBean?
JavaBean越多,spring配置文件就越大,這樣不易維護。為了使配置清晰,我們可以將JavaBean分類管理,放在不同的配置文件中。 應用啟動時將所有的xml同時加載。
比如:
DAO層的JavaBean放到applicationContext-hibernate.xml中,商業邏輯層的JavaBean放到applicationContext-service.xml中。然后啟動類中調用以下代碼載入所有的ApplicationContext。
String[] paths = {"com/yz/spring/dao/hibernate/applicationContext-hibernate.xml",
"com/yz/spring/service/applicationContext-service.xml"};
ctx = new ClassPathXmlApplicationContext(paths);
8、web應用中如何加載ApplicationContext?
可以通過定義web.xml,由web容器自動加載。
context
org.springframework.web.context.ContextLoaderServlet
1
contextConfigLocation /WEB-INF/applicationContext-hibernate.xml /WEB-INF/applicationContext-service.xml
9、在spring中如何配置的log4j?
在web.xml中加入以下代碼即可。
log4jConfigLocation /WEB-INF/log4j.properties
10、Spring框架入門的編程問題解決了,我該如何更深地領會Spring框架呢?
這兩本書你該去看看。這兩本書是由Spring的作者Rod Johnson編寫的。
Expert One on one J2EE Design and Development
Expert One on one J2EE Development Without EJB
你也該看看martinfowler的Inversion of Control Containers and the Dependency Injection pattern。
http://www.martinfowler.com/articles/injection.html
再好好研讀一下spring的文檔。
http://www.jactiongroup.net/reference/html/
大家可能在spring中經常看到這樣的定義:
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="store*">PROPAGATION_REQUIRED</prop>
估計有好多朋友還沒有弄清楚里面的值的意思,仔細看完下面應該知道自己什么情況下面應該使用什么樣的聲明。^_^
Spring中常用事務類型:
EJB的事務類型:
Nerver : 不參與事務,如果參與產生RemoteException
NotSupported: 不能參與
Supports: 如果調用者正在參與事務,相應的EJB調用也可以參與事務,否則不能
Mandatory 如果調用者有一個事務,相應的EJB可以參與事務,否則,TransactionRequiredException
Required 如果調用者有一個事務,相應的EJB可以參與事務,否則,容器將在調用相應的EJB之前,開始一個事務.
當方法調用完成以后,即提交該事務.
RequiresNew 在調用相應的EJB之前,開始一個新的事務,當方法調用返回時,即提交這個事務.
前六個策略類似于EJB CMT:常量名相同,因此,對EJB開發人員來說,應該立刻就感到熟悉。第七個(PROPAGATION_NESTED)是Spring所提供的一個特殊變量。它要求事務管理器或者使用JDBC 3.0 Savepoint API提供嵌套事務行為(如Spring的DataSourceTransactionManager),或者通過JTA支持嵌套事務。
事務屬性中的readOnly標志表示對應的事務應該被最優化為只讀事務。這是一個最優化提示。在一些情況下,一些事務策略能夠起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖“刷新”)。
在事務屬性中還有定義“timeout”值的選項,指定事務超時為幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,并據此得到相應的解釋。
大量采用了callback的機制.
jdbcTemplate.update(...)
jdbcTemplate.query(...)
jdbcTemplate.call(...)
1. 代碼控制的事務管理
簡單配置事務,然后在代碼中使用TransactionTemplate.
2. 參數化配置的事務管理
采用proxy模式,簡單!!!!
(2)hibernate in spring
與上面JDBC中的配置相對比,區別主要在于:
1. SessionFactory的引入
Hibernate中通過SessionFactory創建和維護Session。Spring對
SessionFactory的配置也進行了整合,無需再通過Hibernate.cfg.xml對
SessionFactory進行設定。
SessionFactory節點的mappingResources屬性包含了映射文件的路徑,list
節點下可配置多個映射文件。
hibernateProperties節點則容納了所有的屬性配置。
可以對應傳統的Hibernate.cfg.xml文件結構對這里的SessionFactory配置
進行解讀。
2. 采用面向Hibernate的TransactionManager實現:
org.springframework.orm.hibernate.HibernateTransactionManag
er
public class UserDAO extends HibernateDaoSupport implements IUserDAO
{
public void insertUser(User user) {
getHibernateTemplate().saveOrUpdate(user);
}
}
(3)ibatis in spring
對比之前的JDBC和Hibernate配置,可以看到:
1. sqlMapClient節點
SpringFrameWork Developer’s Guide Version 0.6
類似SessionFactory之與Hibernate,這里我們引入了針對ibatis SqlMap的
SqlMapClientFactoryBean配置。SqlMapClient對于ibatis的意義類似于Session
與Hibernate以及Connection與JDBC,這里的sqlMapClient節點實際上配置了一
個sqlMapClient的創建工廠類。
configLocation屬性配置了ibatis映射文件的名稱。
2. transactionManager節點
這里我們的transactionManager配置與之前JDBC示例中相同,都采用了
DataSourceTransactionManager,這與Hibernate有些差異。
3. userDAO節點
對應的,UserDAO需要配置兩個屬性,sqlMapClient和DataSource,
sqlMapClient將從指定的DataSource中獲取數據庫連接。
其他配置基本上與JDBC示例中相同,這里就不加贅述
(1)與Spring MVC中的Command對象不同,Webwork 中的Model對象,扮演著承上啟下
的角色,它既是Action的輸入參數,又包含了Action處理的結果數據。
換句話說,輸入的Http請求參數,將被存儲在Model對象傳遞給Action進行處理,Action
處理完畢之后,也將結果數據放置到Model 對象中,之后,Model 對象與返回界面融合生
成最后的反饋頁面。
(2)注意這里與Spring MVC 不同,Spring MVC 會自動為邏輯處理單元創建
Command Class實例,但Webwork不會自動為Action創建Model對象實例,
Model 對象實例的創建需要我們在Action 代碼中完成(如LoginAction 中
LoginInfo對象實例的創建)。
(3)
(4)
?<welcome-file-list>
??????? <welcome-file>/web/login/index.jsp</welcome-file>
??? </welcome-file-list>
</web-app>
?<!---Action Definition-->
?<bean id="LoginAction" class="com.jason.action.LoginAction">
??<property name="commandClass">
???<value>com.jason.form.LoginInfo</value>
??</property>
??<property name="fail_view">
???<value>loginfail</value>
??</property>
??<property name="success_view">
???<value>main</value>
??</property>
?</bean>
</beans>
LoginAction
package com.jason.action;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
//導入的時候,之前選擇錯誤
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;???????????????????????
import com.jason.form.LoginInfo;
public class LoginAction extends SimpleFormController {
?
?private String fail_view;
?private String success_view;
?
?protected ModelAndView onSubmit(Object cmd, BindException ex)
?throws Exception {
??LoginInfo loginInfo = (LoginInfo) cmd;
??if (login(loginInfo) == 0) {
???HashMap result_map = new HashMap();
???result_map.put("logininfo", loginInfo);
???List msgList = new LinkedList();
???msgList.add("msg1");
???msgList.add("msg2");
???msgList.add("msg3");
???result_map.put("messages", msgList);
???return new ModelAndView(this.getSuccess_view(), result_map);
??} else {
???return new ModelAndView(this.getFail_view());
??}
??//return new ModelAndView(new RedirectView(“/redirected.jsp”));
?}
?private int login(LoginInfo loginInfo) {
??if ("Erica".equalsIgnoreCase(loginInfo.getUsername())
????&& "mypass".equals(loginInfo.getPassword())) {
???return 0;
??}
??return 1;
?}
?public String getFail_view() {
??return fail_view;
?}
?public String getSuccess_view() {
??return success_view;
?}
?public void setFail_view(String string) {
??fail_view = string;
?}
?public void setSuccess_view(String string) {
??success_view = string;
?}
?
}
LoginInfo
package com.jason.form;
import java.io.Serializable;
public class LoginInfo implements Serializable {
?private String username;
?private String password;
?public String getPassword() {
??return password;
?}
?public void setPassword(String password) {
??this.password = password;
?}
?public String getUsername() {
??return username;
?}
?public void setUsername(String username) {
??this.username = username;
?}
}
【注】調試的時候因為導入的類選擇錯誤引起問題,要注意!!!
(1)Type1 接口注入
加載接口實現并創建其實例的工作由容器完成。在運行期,***實例將由容器提供。
public class MyServlet extends HttpServlet {
????public void doGet(
????HttpServletRequest request,
????HttpServletResponse response)
????throws ServletException, IOException {
???????……
????}
}
這也是一個Type1 型注入,HttpServletRequest和HttpServletResponse實例由Servlet Container在運行期動態注入。
(2)Type2 設值注入
(3)Type3 構造子注入
構造子注入,即通過構造函數完成依賴關系的設定,如:
public class DIByConstructor {
???private final DataSource dataSource;
???private final String message;
???public DIByConstructor(DataSource ds, String msg) {
????this.dataSource = ds;
????this.message = msg;
????}
……
}
Type2 設值注入的優勢
?1. 對于習慣了傳統JavaBean開發的程序員而言,通過setter方法設定依賴關系顯得更加直
?觀,更加自然。
?2. 如果依賴關系(或繼承關系)較為復雜,那么Type3模式的構造函數也會相當龐大(我們需
?要在構造函數中設定所有依賴關系),此時Type2模式往往更為簡潔。
?3. 對于某些第三方類庫而言,可能要求我們的組件必須提供一個默認的構造函數(如Struts
?中的Action),此時Type3類型的依賴注入機制就體現出其局限性,難以完成我們期望的功
?能。
Type3 構造子注入的優勢:
?1. “在構造期即創建一個完整、合法的對象”,對于這條Java設計原則,Type3無疑是最好的
?響應者。
?2. 避免了繁瑣的setter方法的編寫,所有依賴關系均在構造函數中設定,依賴關系集中呈現,
?更加易讀。
?3. 由于沒有setter方法,依賴關系在構造時由容器一次性設定,因此組件在被創建之后即處于
?相對“不變”的穩定狀態,無需擔心上層代碼在調用過程中執行setter方法對組件依賴關系
?產生破壞,特別是對于Singleton模式的組件而言,這可能對整個系統產生重大的影響。
?4. 同樣,由于關聯關系僅在構造函數中表達,只有組件創建者需要關心組件內部的依賴關系。
?對調用者而言,組件中的依賴關系處于黑盒之中。對上層屏蔽不必要的信息,也為系統的
?層次清晰性提供了保證。
?5. 通過構造子注入,意味著我們可以在構造函數中決定依賴關系的注入順序,對于一個大量
?依賴外部服務的組件而言,依賴關系的獲得順序可能非常重要,比如某個依賴關系注入的
?先決條件是組件的DataSource及相關資源已經被設定。