jsp頁面的代碼:
1,在今天整理代碼的時候,發(fā)現(xiàn)原來的一段代碼,前臺合并單元格。
需要在后端,原來的列表基礎(chǔ)上,再增加一層。
頁面上操作,struts2
這樣根據(jù)code在頁面上就會顯示分組合并單元格的效果。
就可以使用延遲加載了,spring通過filter的方式對綁定hibernate session 到request的線程中。
that binds a Hibernate Session to the thread for the entire processing of the request
剛開始我是把上面這段配置隨便放到web.xml中,一致不成功總報session 關(guān)閉,不起作用,最后查了一下,我把這個filter放到了struts的filter之上,就可以了。
說明FlushMode有五種屬性
1 NEVEL
2 MANUAL
3 AUTO
4 COMMIT
5 ALWAYS
我用的是Struts2基類代碼,如下
先說一下:
一,struts2的ModelDriven (下面來源網(wǎng)絡(luò))
可以根據(jù)Action屬性的不同將它分為兩類:Field-Driven(屬性驅(qū)動) Action和Model-Driven(模型驅(qū)動) Action。
一、Field-Driven(屬性驅(qū)動)Action,Action擁有自己的屬性,這些屬性一般是Java的基本類型。表單字段直接和Action的屬性 對應(yīng)。
二、實現(xiàn)了modelDriven接口可以在action中直接獲得例如User對象,它會將Object getModel()取得的User放到ValueStack中。可以理解為將這個User的屬性追加到Action中。它主要是作用是實現(xiàn)類似 Struts的FormBean功能。
在struts2中,提供了一種直接使用領(lǐng)域?qū)ο蟮姆绞剑褪亲宎ction實現(xiàn)com.opensymphony.xwork2.ModelDriven接口,ModelDriven讓你可以直接操作應(yīng)用程序中的領(lǐng)域?qū)ο螅试S你在web層和業(yè)務(wù)層使用相同的對象。
ModelDriven接口只有一個方法
public Object getModel() {
return null;
}
該方法返回一個用于接收用戶輸入數(shù)據(jù)的對象模型,在這個模型對象中的屬性可以直接通過(屬性名)userName來訪問,而不需要使用(對象名.屬 性名)user.userName這種格式來訪問了,在action也不需要對對象提供getter和setter方法了,但是必須要在action中進(jìn) 行new操作
如下
// ModelDriven要使用泛型哦
public class LoginAction extends ActionSupport implements ModelDriven<User>{
private static final long serialVersionUID = -6434128483294080524L;
//這里必須要new
private User user=new User();
public String login() throws Exception {
// TODO Auto-generated method stub
return SUCCESS;
}
//這里是實現(xiàn)接口方法
@Override
public User getModel() {
// TODO Auto-generated method stub
//別忘記了,要把返回值寫上哦
return user;
}
}
這樣一個ModelDriven就實現(xiàn)完畢了
和屬性驅(qū)動的Action有很大的區(qū)別,下面一一列舉:
(1)模型驅(qū)動的Action必須實現(xiàn)ModelDriven接口,而且要提供相應(yīng)的泛型,這里當(dāng)然就是具體使用的Java Bean了。
(2)實現(xiàn)ModelDriven的getModel方法,其實就是簡單的返回泛型的一個對象。
(3)在Action提供一個泛型的私有對象,這里就是定義一個User的user對象,并提供相應(yīng)的getter與setter。
好了,上面的三件事做完之后,Action就會去自動調(diào)用User的setter將表單中的name屬性的值賦給User中的屬性。而Action的后續(xù)處理的Jsp頁面后者是Servlet就可以使用user對象了。
到底是用屬性驅(qū)動和是模型驅(qū)動呢?
這個問題困擾了很多Struts2的初學(xué)者,我這里提供一些建議:
(1)請你統(tǒng)一整個系統(tǒng)中的Action使用的驅(qū)動模型,即要么都是用屬性驅(qū)動,要么都是用模型驅(qū)動。
(2)如果你的DB中的持久層的對象與表單中的屬性都是一一對應(yīng)的話,那么就使用模型驅(qū)動吧,畢竟看起來代碼要整潔得多。
(3)如果表單的屬性不是一一對應(yīng)的話,那么就應(yīng)該使用屬性驅(qū)動,否則,你的系統(tǒng)就必須提供兩個Bean,一個對應(yīng)表單提交的數(shù)據(jù),另一個用與持久層。
二,持久層基類 HibernateDao
代碼如:
上面的代碼,基類沒有使用HibernateDaoSupport,我們需要自己引入SessionFactory。
持久層基類,一般Spring的Hibernate ORM 框架帶來了方便的HibernateDaoSupport類,你的DAO類可以繼承它:
public class DaoHibernate extends HibernateDaoSupport {
.................
}
如果你選擇這種設(shè)計,就需要動態(tài)注入SessionFactory而HibernateDaoSupport包含這個屬性.這個類提供了一個方便的方法getHibernateTemplate(); 就能得到HibernateTemplate的一個實例.它也有g(shù)etSession()和releaseSession,以便于你應(yīng)為某些原因而不使用HibernateTempate的情況下執(zhí)行Hibernate操作。
HibernateDaoSupport提供了基于AOP事務(wù)的自動處理,程序員完全可以不用理會事務(wù)的開始與提交。在JDBC中一個Connection對象使用一個事務(wù),那么在Hibernate中一個事務(wù)肯定要關(guān)聯(lián)一個SessionFactory了,然而這個SessionFactory卻沒有在DAO中體現(xiàn)。其實主要的原因是HibernateDaoSupport類已經(jīng)默默地做了封裝的工作,它用一個setSessionFactory方法將SessionFactory進(jìn)行注入,所以繼承自HibernateDaoSupport類的DAO都會具有SessionFactory的屬性,從而可以通過SessionFactory創(chuàng)建Session實例操作數(shù)據(jù)庫。
如果使用像 public class HibernateDao<T, PK extends Serializable> 這樣的泛型基類就會有問題,可以拿個T代表任意類型,Java的泛型拿不到T.class,就無法得到類對象, 如下面的clazz,
public T get(final PK id) {
Assert.notNull(id, "id不能為空");
return (T) getSession().load(clazz, id);
}
最后在網(wǎng)上找到了解決方案,可以使用泛型public class HibernateDao<T, PK extends Serializable>基類了。
重點這句: entityClass =(Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
spring bean 定義可能包含大量的配置信息,包括容器相關(guān)的信息(比如初始化方法,靜態(tài)工廠方法
等)、構(gòu)造函數(shù)參數(shù)、屬性等。如果兩個bean之間的配置信息大同小異,可采用bean的繼承來減少重
復(fù)配置工作。子bean定義可以從父bean定義繼承部分配置。它也可覆蓋一些配置,或者添加一些配置
。使用繼承配置可以節(jié)省很多輸入工作,實際上就是一種模板形式。
spring中事務(wù)配置中就有這樣例子,為了使用事務(wù)只要父配置了事務(wù)代理就可以了,所有需要事務(wù)的
bean只要繼承父就可以了。說到這個就在多說幾句,父bean通常不需要實例化的,而僅僅作為子bean
定的的模板使用;而ApplicationContext默認(rèn)預(yù)初始化所有的singleton bean。為了阻止父bean被預(yù)
初始化,可以使用abstract屬性設(shè)置父bean為抽象bean。容器會忽略所有的抽象bean定義,預(yù)初始化
時不初始化抽象bean。
2, spring 事務(wù)管理
傳統(tǒng)的J2EE開發(fā)者對事務(wù)管理可能采用兩種策略
(1),全局事務(wù):全局事務(wù)通常由應(yīng)用服務(wù)器管理,使用JTA。全局事務(wù)可跨越多個事務(wù)性的資源,保證
在多個事務(wù)性資源間跨越時資源一致性。
(2),局部事務(wù):局部事務(wù)和特定資源相關(guān),如,一個和JDBC鏈接關(guān)聯(lián)的事務(wù)。該事務(wù)盡能保證對該
JDBC連接數(shù)據(jù)庫的一致性,對局部事務(wù),應(yīng)用服務(wù)器不需要參與事務(wù)管理,不能保證跨越多個資源的
事務(wù)正確性。
3,編程式事務(wù)
Spring 提供兩種編程式的事務(wù)管理
(1)使用TransactionTemplate事務(wù)管理
(2)直接使用一個PlatformTransactionManager實現(xiàn)類管理事務(wù)。
兩種編程式的事務(wù)都不需要與特定的事務(wù)API耦合,第一種更符合Spring模板式的編程模型,因此通常推薦采用第一種方式,第二種非常類似于JTA的UserTransaction的API編程,區(qū)別是減少了異常處理。
4,聲明式事務(wù)
Spring的聲明式事務(wù)是通過面向切面(AOP)實現(xiàn)。
(1)使用聲明式事務(wù)管理
通常,通過TransactionPoxyFactoryBean為目標(biāo)Bean生成Spring事務(wù)代理。當(dāng)bean實例的方法需要事務(wù)管理時,采用TransactionPoxyFactoryBean來自目標(biāo)bean生成事務(wù)代理。每個TransactionPoxyFactoryBean為一個具體的目標(biāo)bean生成代理對象,代理對象的方法改寫了目標(biāo)bean的方法,就是在目標(biāo)bean的方法執(zhí)行之前加入開始事務(wù),在目標(biāo)bean方法結(jié)束之后提交事務(wù),遇到指定異常回滾事務(wù)。
定義事務(wù)代理bean模板
(2)根據(jù)BeanName自動創(chuàng)建事務(wù)代理
如果同一個應(yīng)用中有很多目標(biāo)bean需要生成事務(wù)代理,當(dāng)然可以為每個目標(biāo)bean額外配置一個TransactionPoxyFactoryBean bean.這樣做的缺點是,配置文件相當(dāng)臃腫而且難以維護(hù),此時可以考慮使用自動事務(wù)代理。自動事務(wù)代理的思路是,當(dāng)ApplicationContext初始化完成后,由上下文中的某個bean"后處理"每個目標(biāo)bean,為這些目標(biāo)bean生成事務(wù)代理。
能為目標(biāo)bean執(zhí)行"后處理"的bean必須實現(xiàn)BeanFactoryPostProcessor接口,ApplicationContext完成初始化后,會自動初始化所有實現(xiàn)BeanFactoryPostProcessor接口的bean,并且讓它“后處理”其他bean.Spring提供BeanFactoryPostProcessor的實現(xiàn)類BeanNameAutoPoxyCreator,BeanNameAutoPoxyCreator可以用來處理ApplicationContext中其他bean,方法是通過名稱來識別,并且把他們用事務(wù)代理包裝起來。BeanNameAutoPoxyCreator生成的事務(wù)代理,和使用TransactionPoxyFactoryBean生成的事務(wù)代理基本一致。
定義事務(wù)攔截bean
次配置關(guān)鍵在兩個bean
TransactionInterceptor
BeanNameAutoProxyCreator
(3)基于注釋式事務(wù)代理配置
當(dāng)采用XML描述配置元數(shù)據(jù)時,將通過<bean/>元素的class屬性來指定實例化對象的類型。class 屬性 (對應(yīng)BeanDefinition實例的Class屬性)通常是必須的(不過也有兩種例外的情形,“使用實例工廠方法實例化”和“bean定義的繼承”)。class屬性主要有兩種用途:在大多數(shù)情況下,容器將直接通過反射調(diào)用指定類的構(gòu)造器來創(chuàng)建bean(這有點等類似于在Java代碼中使用new操作符);在極少數(shù)情況下,容器將調(diào)用類的靜態(tài)工廠方法來創(chuàng)建bean實例,class屬性將用來指定實際具有靜態(tài)工廠方法的類(至于調(diào)用靜態(tài)工廠方法創(chuàng)建的對象類型是當(dāng)前class還是其他的class則無關(guān)緊要)。
2, 延遲初始化bean
ApplicationContext實現(xiàn)的默認(rèn)行為就是在啟動時將所有singleton bean提前進(jìn)行實例化。提前實例化意味著作為初始化過程的一部分,ApplicationContext實例會創(chuàng)建并配置所有的singleton bean。通常情況下這是件好事,因為這樣在配置中的任何錯誤就會即刻被發(fā)現(xiàn)(否則的話可能要花幾個小時甚至幾天)。
有時候這種默認(rèn)處理可能并不是你想要的。如果你不想讓一個singleton bean在ApplicationContext實現(xiàn)在初始化時被提前實例化,那么可以將bean設(shè)置為延遲實例化。一個延遲初始化bean將告訴IoC 容器是在啟動時還是在第一次被用到時實例化。
在XML配置文件中,延遲初始化將通過<bean/>元素中的lazy-init屬性來進(jìn)行控制。例如:
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true">
<!-- various properties here... -->
</bean>
<bean name="not.lazy" class="com.foo.AnotherBean">
<!-- various properties here... -->
</bean>
當(dāng)ApplicationContext實現(xiàn)加載上述配置時,設(shè)置為lazy的bean將不會在ApplicationContext啟動時提前被實例化,而not.lazy卻會被提前實例化。
需要說明的是,如果一個bean被設(shè)置為延遲初始化,而另一個非延遲初始化的singleton bean依賴于它,那么當(dāng)ApplicationContext提前實例化singleton bean時,它必須也確保所有上述singleton 依賴bean也被預(yù)先初始化,當(dāng)然也包括設(shè)置為延遲實例化的bean。因此,如果Ioc容器在啟動的時候創(chuàng)建了那些設(shè)置為延遲實例化的bean的實例,你也不要覺得奇怪,因為那些延遲初始化的bean可能在配置的某個地方被注入到了一個非延遲初始化singleton bean里面。
在容器層次中通過在<beans/>元素上使用'default-lazy-init'屬性來控制延遲初始化也是可能的。如下面的配置:
<beans default-lazy-init="true">
<!-- no beans will be eagerly pre-instantiated... -->
</beans>
3,自動裝配(autowire)協(xié)作者
Spring IoC容器可以自動裝配(autowire)相互協(xié)作bean之間的關(guān)聯(lián)關(guān)系。因此,如果可能的話,可以自動讓Spring通過檢查BeanFactory中的內(nèi)容,來替我們指定bean的協(xié)作者(其他被依賴的bean)。由于autowire可以針對單個bean進(jìn)行設(shè)置,因此可以讓有些bean使用autowire,有些bean不采用。autowire的方便之處在減少或者消除屬性或構(gòu)造器參數(shù)的設(shè)置,這樣可以給我們的配置文件減減肥![2] 在xml配置文件中,autowire一共有五種類型,可以在<bean/>元素中使用autowire屬性指定:
Table 3.2. Autowiring modes
模式 說明
no 不使用自動裝配。必須通過ref元素指定依賴,這是默認(rèn)設(shè)置。由于顯式指定協(xié)作者可以使配置更靈活、更清晰,因此對于較大的部署配置,推薦采用該設(shè)置。而且在某種程度上,它也是系統(tǒng)架構(gòu)的一種文檔形式。
byName 根據(jù)屬性名自動裝配。此選項將檢查容器并根據(jù)名字查找與屬性完全一致的bean,并將其與屬性自動裝配。例如,在bean定義中將autowire設(shè)置為by name,而該bean包含master屬性(同時提供setMaster(..)方法),Spring就會查找名為master的bean定義,并用它來裝配給master屬性。
byType 如果容器中存在一個與指定屬性類型相同的bean,那么將與該屬性自動裝配。如果存在多個該類型的bean,那么將會拋出異常,并指出不能使用byType方式進(jìn)行自動裝配。若沒有找到相匹配的bean,則什么事都不發(fā)生,屬性也不會被設(shè)置。如果你不希望這樣,那么可以通過設(shè)置dependency-check="objects"讓Spring拋出異常。
constructor 與byType的方式類似,不同之處在于它應(yīng)用于構(gòu)造器參數(shù)。如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的bean,那么將會拋出異常。
autodetect 通過bean類的自省機(jī)制(introspection)來決定是使用constructor還是byType方式進(jìn)行自動裝配。如果發(fā)現(xiàn)默認(rèn)的構(gòu)造器,那么將使用byType方式。
如果直接使用property和constructor-arg注入依賴的話,那么將總是覆蓋自動裝配。而且目前也不支持簡單類型的自動裝配,這里所說的簡單類型包括基本類型、String、Class以及簡單類型的數(shù)組(這一點已經(jīng)被設(shè)計,將考慮作為一個功能提供)。自動裝配還可以與依賴檢查結(jié)合使用,這樣依賴檢查將在自動裝配完成之后被執(zhí)行。
理解自動裝配的優(yōu)缺點是很重要的。其中優(yōu)點包括:
自動裝配能顯著減少配置的數(shù)量。不過,采用bean模板(見這里)也可以達(dá)到同樣的目的。
自動裝配可以使配置與java代碼同步更新。例如,如果你需要給一個java類增加一個依賴,那么該依賴將被自動實現(xiàn)而不需要修改配置。因此強(qiáng)烈推薦在開發(fā)過程中采用自動裝配,而在系統(tǒng)趨于穩(wěn)定的時候改為顯式裝配的方式。
自動裝配的一些缺點:
盡管自動裝配比顯式裝配更神奇,但是,正如上面所提到的,Spring會盡量避免在裝配不明確的時候進(jìn)行猜測,因為裝配不明確可能出現(xiàn)難以預(yù)料的結(jié)果,而且Spring所管理的對象之間的關(guān)聯(lián)關(guān)系也不再能清晰的進(jìn)行文檔化。
對于那些根據(jù)Spring配置文件生成文檔的工具來說,自動裝配將會使這些工具沒法生成依賴信息。
如果采用by type方式自動裝配,那么容器中類型與自動裝配bean的屬性或者構(gòu)造函數(shù)參數(shù)類型一致的bean只能有一個,如果配置可能存在多個這樣的bean,那么就要考慮采用顯式裝配了。
盡管使用autowire沒有對錯之分,但是能在一個項目中保持一定程度的一致性是最好的做法。例如,通常情況下如果沒有使用自動裝配,那么僅自動裝配一個或兩個bean定義可能會引起開發(fā)者的混淆。
Ehcache支持的分布式緩存支持有三種RMI,JGroups,JMS
這里介紹下MRI和JGrpups兩種方式,Ehcache使用版本為1.5.0,關(guān)于ehcache的其他信息請參考http://ehcache.sourceforge.net/EhcacheUserGuide.html,關(guān)于jgroups的信息請參考http://www.jgroups.org/manual/html_single/index.html。
原始文章 http://www.javaeye.com/topic/335623
它是一種可以接收從internet 或者internet 上的其他系統(tǒng)傳遞過來的請求的輕量級獨立的通信技術(shù)。這種技術(shù)允許網(wǎng)絡(luò)上的所有系統(tǒng)進(jìn)行交互。
j2ee平臺是圍繞web服務(wù)來構(gòu)架的,其中的技術(shù)和web服務(wù)相關(guān)的有JAX-RCP 、Web Service、SAAJ 、JAXR 、EJB 、JAC 等,其中Web Services for J2EE 是WEB服務(wù)總框架,JAX-RCP是J2EE的WEB服務(wù)的核心技術(shù),SAAJ為處理帶附件的SOAP消息提供了JAVA編程API.
在J2EE平臺中,要開發(fā)WEB服務(wù)可以使用兩種技術(shù),一種基于XML遠(yuǎn)程調(diào)用的技術(shù)-JAX-RCP,另外一個基于XML的消息發(fā)送技術(shù)-JAXM.
這里主要針對JAX-RCP 詳細(xì)說一下。
JAX-RCP( JAVA API FOR XMLBASED RCP) 是一種遠(yuǎn)程方法調(diào)用(或者說遠(yuǎn)程過程調(diào)用),那么它和其他遠(yuǎn)程方法調(diào)用(RPC,COM,CORBA RMI)有什么區(qū)別呢
綜合比較長遠(yuǎn)的遠(yuǎn)程方法調(diào)用技術(shù),他們有以下共性。
1,在客戶端和服務(wù)端有通用的編程接口。
2,在客戶端STUB,在服務(wù)端有SKELETON.
3,客戶端和服務(wù)端有專門的協(xié)議進(jìn)行數(shù)據(jù)傳輸。
對于通用接口的描述,比如CORBA 有IDL OF CORBA ,JAVA RMI 有JAVA RMI INTERFACE IN RMI ,對于基于XML的RPC 來說,IDL 就是WSDL。那么對于XML-RPC來說,這個結(jié)構(gòu)中“傳輸協(xié)議”當(dāng)然是SAOP,SOAP消息是將以傳輸文本為基礎(chǔ)的協(xié)議(HTTP,SMTP FTP)作為載體來使用的。也就是說,SOAP消息的傳輸建立在HTTP SMTP FTP之上。
JAX-RCP的客戶端調(diào)用方法:
1,基于STUB
2,動態(tài)代理
3,動態(tài)調(diào)用
就拿hibernate來說吧,他支持hql查詢,在我們組裝sql語句時,需要注意幾個問題:
1、要查詢當(dāng)然離不開數(shù)據(jù)庫,我們建表時,默認(rèn)的主鍵都是索引,這里要注意的就是關(guān)于建立單個索引和復(fù)合索引了。
具體的索引的hibernate中也是適用,我發(fā)現(xiàn)好多人用hibernate就很少提到索引這個概念了(用ibatis自己寫sql就會關(guān)注索引字段,這個還是可以的額)
索引的引用規(guī)則都是適用的:
介紹下:單個索引就是出現(xiàn)索引字段作為條件就應(yīng)用 ;
復(fù)合索引(假設(shè)是2個字段的復(fù)合索引),出現(xiàn)復(fù)合索引的第一個字段作為條件就應(yīng)用;
出現(xiàn)復(fù)合索引的2個字段作為條件,這應(yīng)用,如果沒有出現(xiàn)復(fù)合索引的第一個字段則不應(yīng)用;
由此我們需要為我們的數(shù)據(jù)庫建立索引,記住復(fù)合索引是有順序的 。
影響我們建立索引的條件還有就是業(yè)務(wù)(這個很重要) ,舉個例子:如果有2個查詢條件(性別、所在部門),倘若我們要建立符合索引,
那么我們應(yīng)該將"所在部門"字段放在前面,"性別"放在后面,主要是因為,如果某個地方的查詢條件只有"所在部門",也可以起作用。另外要注意,如果查詢索引字段參與函數(shù)計算和like等,那么索引也不起作用。
2、 在我們寫查詢代碼時,盡量對應(yīng)各個表的已經(jīng)存在索引寫查詢條件
[第一個查詢條件盡量是單個索引,或者是復(fù)合索引的第一個字段] 。
3、還有就是大家再拼裝查詢語句時,傳入的查詢條件值盡量不要直接寫在查詢語句中,而是要以參數(shù)的方式提供即使用綁定參數(shù),
這樣,系統(tǒng)多次調(diào)用統(tǒng)一個查詢時(比如:select * from TestVO where code = ? [不要寫為 select * from TestVO where code = 'aaaa']) ,
條件值都是以參數(shù)的方式提供的,這樣,多次查詢雖然參數(shù)值不一樣,但查詢語句相同,數(shù)據(jù)庫只有第一次才對查詢語句進(jìn)行編譯,
以后則不在編譯,所以性能會有提升。
用參數(shù)的方式還有一個好處是:如果你不是使用
Criteria criteria = openSession().createCriteria(**PO.class);
criteria.add(Restrictions.like( "name",convertDBString(name) ));
的方式,而是使用hibernate的hql的話,那么如果參數(shù)值為中文會有問題,用參數(shù)可以解決這個問題。
注: 使用綁定參數(shù)的優(yōu)勢:
我們?yōu)槭裁匆褂媒壎麉?shù)?任何一個事物的存在都是有其價
值的,具體到綁定參數(shù)對于HQL查詢來說,主要有以下兩個主要優(yōu)勢:
①、 可以利用數(shù)據(jù)庫實施性能優(yōu)化,因為對Hibernate來說在底層
使用的是PrepareStatement來完成查詢,因此對于語法相同參數(shù)不同的
SQL語句,可以充分利用預(yù)編譯SQL語句緩存,從而提升查詢效率。
②、 可以防止SQL Injection安全漏洞的產(chǎn)生:
![]() 圖1 Servlet線程池 |
Import javax.servlet. *; Import javax.servlet.http. *; Import java.io. *; Public class Concurrent Test extends HttpServlet {PrintWriter output; Public void service (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username; Response.setContentType ("text/html; charset=gb2312"); Username = request.getParameter ("username"); Output = response.getWriter (); Try {Thread. sleep (5000); //為了突出并發(fā)問題,在這設(shè)置一個延時 } Catch (Interrupted Exception e){} output.println("用戶名:"+Username+"<BR>"); } } |
![]() 圖2 a用戶和b用戶的瀏覽器輸出 |
![]() 圖3 Servlet實例的JMM模型 |
調(diào)度時刻 | a線程 | b線程 |
T1 | 訪問Servlet頁面 | |
T2 | 訪問Servlet頁面 | |
T3 | output=a的輸出username=a休眠5000毫秒,讓出CPU | |
T4 | output=b的輸出(寫回主存)username=b休眠5000毫秒,讓出CPU | |
T5 | 在用戶b的瀏覽器上輸出a線程的username的值,a線程終止。 | |
T6 | 在用戶b的瀏覽器上輸出b線程的username的值,b線程終止。 |
Public class Concurrent Test extends HttpServlet implements SingleThreadModel { ………… } |
………… Public class Concurrent Test extends HttpServlet { ………… Username = request.getParameter ("username"); Synchronized (this){ Output = response.getWriter (); Try { Thread. Sleep (5000); } Catch (Interrupted Exception e){} output.println("用戶名:"+Username+"<BR>"); } } } |
…… Public class Concurrent Test extends HttpServlet {public void service (HttpServletRequest request, HttpServletResponse Response) throws ServletException, IOException { Print Writer output; String username; Response.setContentType ("text/html; charset=gb2312"); …… } } |
2)此外,相應(yīng)的,最有效率的交流方式必須留給web開發(fā),那就是face2face(面對面),不要太擔(dān)心你的設(shè)計不能被完備的文檔所保留下來,他們會以交流,代碼和小卡片的方式保存下來
3)人的因素會更加重要,無論是對用戶的需求,還是開發(fā)人員的素質(zhì)。
另:有關(guān)web效率,有著名的14條規(guī)則,由yahoo性能效率小組所總結(jié),并廣為流傳。業(yè)已出現(xiàn)相關(guān)插件(YSlow),14 rules列在下面:
減少http請求次數(shù)
Image maps 圖像中增加url可以將多個圖片合為一個,減少http請求。
CSS Sprites 通過css 將圖片引入到頁面中減少頁面請求http 。
Combined files合并文件不如合并多個請求的javascript為一個。減少http請求。
http://developer.yahoo.net/blog/archives/2007/04/rule_1_make_few.html
2. Use a Content Delivery Network
在下載的css、js、image組件里增加過期時間
(對下載的組件進(jìn)行壓縮)
毫無疑問,對站點內(nèi)容進(jìn)行壓縮是一個比較常用的 Web 優(yōu)化手段.但是并不一定都能達(dá)到理想的效果.原因在于 mod-gzip 模塊不但消耗服務(wù)器端 CPU資源,也消耗客戶端 CPU資源. 而且, mod_gzip 壓縮文件后創(chuàng)建的臨時文件是放到磁盤上的,這也會給磁盤 IO帶來嚴(yán)重的問題.
Flickr 采用的是 Httpd 2.x 以后支持的 mod_deflate 模塊.壓縮操作都在內(nèi)存中進(jìn)行.mod_deflate 在 Httpd 1.x 是不可用的, 不過可以通過創(chuàng)建 RAM盤的方式來間接提高性能.
當(dāng)然, mod_gzip 到也不是一無是處, 對于預(yù)壓縮的文件, 還是有好處的. 而且, 采用壓縮的時候,也要注意策略. 圖片文件壓縮就沒什么必要了(Flickr 上圖像多, 而且壓縮得不到什么好處). Flickr 只對JavaScript 和 CSS進(jìn)行壓縮. mod_gzip 新一點的版本能夠自動通過配置 mod_gzip_update_static 選項自動處理預(yù)壓縮的文件. Cal 也指出這個特性在一些舊版本的瀏覽器上會出問題.
壓縮的另一個主要手段是內(nèi)容的壓縮. 針對 JavaScript 可以進(jìn)行通過減少注釋、合并空格、使用緊湊的語法等小技巧(Google 的所有腳本都非常難讀,而且非常緊湊,思想類似).當(dāng)然,經(jīng)過這樣處理的 JavaScript 可能帶了很多括號不容易解析,Flickr 使用了 Dojo Compressor 來構(gòu)建解析樹。Dojo Compressor 開銷很低,而且對于最終用戶是透明的. JavaScript 的處理方法介紹過,CSS 處理則相對簡單.通過簡單的正則表達(dá)式替換(比如把多個空格替換為一個空格符), 最高可以獲得 50% 的壓縮比。
css文件盡可能放在頁面的最上面
js文件盡可能放在頁面的最下面
6。Put JS components as close to the bottom of the page as possible.
(js文件盡可能放在頁面的最下面)
7。Avoid CSS Expressions
(在css文件中慎用表達(dá)式)
8。Make JavaScript and CSS External
(在外部包含js和css文件)
9。Reduce DNS Lookups
(減少請求中域名的解析次數(shù))
10。Minify JavaScript
(js代碼壓縮)
11。Avoid doing redirects.
(避免重定向)
12。Remove Duplicates Scripts
(避免請求重復(fù)的js文件)
13。Configure ETags
(配置好ETag)
Flickr 的開發(fā)者充分利用了 Http 1.1 規(guī)范定義的 Etag 與 Last-Modified 機(jī)制 來提高 Caching 的效率. 值得注意的是,Cal 介紹了一個在負(fù)載均衡條件下的 e-Tag 小技巧. 即可以設(shè)定 Apache 通過文件調(diào)整時間與文件大小獲得 E-Tag ,而默認(rèn)情況下, Apache 是通過文件節(jié)點獲取 e-Tag 的。當(dāng)然,這也不是很完美,因為會影響 if-modified-since 。
但是有的網(wǎng)站的e-Tag,如yahoo,其產(chǎn)生規(guī)則是基于節(jié)點的。相同的css或js腳本在不同節(jié)點服務(wù)器上的e-Tag不同,所以如果有n個服務(wù)器,那么瀏覽器獲得304應(yīng)答消息的概率是1/n。
14。Make Ajax Cacheable
(緩存Ajax請求)
以下幾點是新增的準(zhǔn)則,還沒有正式公布,所以大家要注意,
15。Flush the Header
(先發(fā)送Header里的信息)
We improved the page load times by flushing the apache output buffer after the document HEAD was generated.This had two benefits.
First, the HEAD contains SCRIPT and LINK tags for scripts and stylesheets. By flushing the HEAD, those tags are received and parsed by the browser sooner, and in turn the browser starts downloading those components earlier.
Second, the HEAD is flushed before actually generating the search results. This is a win for any property doing a significant backend computation or especially making one or more backend web service calls.
16。Split Static Content Across Multiple Hostnames
(把較大的靜態(tài)文件分割成不同域的請求)
If you have many (10 or more) components downloaded from a single hostname, it might be better to split those across two hostnames.
17。Reduce the Size of Cookies
(不要讓Cookie內(nèi)容過大)
Reduce the amount of data in the cookie by storing state information on the backend, and abbreviating names and values stored in the cookie. Set expiration dates on your cookies, and make them as short as possible.
18。Host Static Content on a Different Top-Level Domain
(把靜態(tài)文件放在不同的頂級域名下)
19。Minify CSS
(Css代碼壓縮)
20。Use GET for XHR
(有XHR時使用GET請求)
Iain Lamb did a deep study of how using POST for XMLHttpRequests is inefficient, especially in IE. His recommendation: “If the amount of data you have to send to the server is small (less than 2k), I suggest you design your webservice / client application to use GET rather than POST。
21。Avoid IFrames
(盡量避免使用IFrame)
Don’t use SRC (set it via JS instead). Each IFrame takes 20-50ms, even if it contains nothing
22。Optimize images
(優(yōu)化圖片)
(2)定時控制--定時的格式(網(wǎng)上總結(jié))
一個Cron-表達(dá)式是一個由六至七個字段組成由空格分隔的字符串,其中6個字段是必須的而一個是可選的,如下:
字段名 | 允許的值 | 允許的特殊字符 | ||
---|---|---|---|---|
秒 |
0-59 |
, - * / |
||
分 |
0-59 |
, - * / |
||
小時 |
0-23 |
, - * / |
||
日 |
1-31 |
, - * ? / L W C |
||
月 |
1-12 or JAN-DEC |
, - * / |
||
周幾 |
1-7 or SUN-SAT |
, - * ? / L C # |
||
年 (可選字段) |
empty, 1970-2099 |
, - * / |
'*' 字符可以用于所有字段,在“分”字段中設(shè)為"*"表示"每一分鐘"的含義。
'?' 字符可以用在“日”和“周幾”字段. 它用來指定 '不明確的值'. 這在你需要指定這兩個字段中的某一個值而不是另外一個的時候會被用到。在后面的例子中可以看到其含義。
'-' 字符被用來指定一個值的范圍,比如在“小時”字段中設(shè)為"10-12"表示"10點到12點".
',' 字符指定數(shù)個值。比如在“周幾”字段中設(shè)為"MON,WED,FRI"表示"the days Monday, Wednesday, and Friday".
'/' 字符用來指定一個值的的增加幅度. 比如在“秒”字段中設(shè)置為"0/15"表示"第0, 15, 30, 和 45秒"。而 "5/15"則表示"第5, 20, 35, 和 50". 在'/'前加"*"字符相當(dāng)于指定從0秒開始. 每個字段都有一系列可以開始或結(jié)束的數(shù)值。對于“秒”和“分”字段來說,其數(shù)值范圍為0到59,對于“小時”字段來說其為0到23, 對于“日”字段來說為0到31, 而對于“月”字段來說為1到12。"/"字段僅僅只是幫助你在允許的數(shù)值范圍內(nèi)從開始"第n"的值。 因此 對于“月”字段來說"7/6"只是表示7月被開啟而不是“每六個月”, 請注意其中微妙的差別。
'L'字符可用在“日”和“周幾”這兩個字段。它是"last"的縮寫, 但是在這兩個字段中有不同的含義。例如,“日”字段中的"L"表示"一個月中的最后一天" —— 對于一月就是31號對于二月來說就是28號(非閏年)。而在“周幾”字段中, 它簡單的表示"7" or "SAT",但是如果在“周幾”字段中使用時跟在某個數(shù)字之后, 它表示"該月最后一個星期×" —— 比如"6L"表示"該月最后一個周五"。當(dāng)使用'L'選項時,指定確定的列表或者范圍非常重要,否則你會被結(jié)果搞糊涂的。
'W' 可用于“日”字段。用來指定歷給定日期最近的工作日(周一到周五) 。比如你將“日”字段設(shè)為"15W",意為: "離該月15號最近的工作日"。因此如果15號為周六,觸發(fā)器會在14號即周五調(diào)用。如果15號為周日, 觸發(fā)器會在16號也就是周一觸發(fā)。如果15號為周二,那么當(dāng)天就會觸發(fā)。然而如果你將“日”字段設(shè)為"1W", 而一號又是周六, 觸發(fā)器會于下周一也就是當(dāng)月的3號觸發(fā),因為它不會越過當(dāng)月的值的范圍邊界。'W'字符只能用于“日”字段的值為單獨的一天而不是一系列值的時候。
'L'和'W'可以組合用于“日”字段表示為'LW',意為"該月最后一個工作日"。
'#' 字符可用于“周幾”字段。該字符表示“該月第幾個周×”,比如"6#3"表示該月第三個周五( 6表示周五而"#3"該月第三個)。再比如: "2#1" = 表示該月第一個周一而 "4#5" = 該月第五個周三。注意如果你指定"#5"該月沒有第五個“周×”,該月是不會觸發(fā)的。
'C' 字符可用于“日”和“周幾”字段,它是"calendar"的縮寫。 它表示為基于相關(guān)的日歷所計算出的值(如果有的話)。如果沒有關(guān)聯(lián)的日歷, 那它等同于包含全部日歷。“日”字段值為"5C"表示"日歷中的第一天或者5號以后",“周幾”字段值為"1C"則表示"日歷中的第一天或者周日以后"。
對于“月份”字段和“周幾”字段來說合法的字符都不是大小寫敏感的。
下面是一些完整的例子:
表達(dá)式 | 含義 | |
---|---|---|
"0 0 12 * * ?" |
每天中午十二點觸發(fā) |
|
"0 15 10 ? * *" |
每天早上10:15觸發(fā) |
|
"0 15 10 * * ?" |
每天早上10:15觸發(fā) |
|
"0 15 10 * * ? *" |
每天早上10:15觸發(fā) |
|
"0 15 10 * * ? 2005" |
2005年的每天早上10:15觸發(fā) |
|
"0 * 14 * * ?" |
每天從下午2點開始到2點59分每分鐘一次觸發(fā) | |
"0 0/5 14 * * ?" |
每天從下午2點開始到2:55分結(jié)束每5分鐘一次觸發(fā) | |
"0 0/5 14,18 * * ?" |
每天的下午2點至2:55和6點至6點55分兩個時間段內(nèi)每5分鐘一次觸發(fā) | |
"0 0-5 14 * * ?" |
每天14:00至14:05每分鐘一次觸發(fā) | |
"0 10,44 14 ? 3 WED" |
三月的每周三的14:10和14:44觸發(fā) | |
"0 15 10 ? * MON-FRI" |
每個周一、周二、周三、周四、周五的10:15觸發(fā) | |
"0 15 10 15 * ?" |
每月15號的10:15觸發(fā) | |
"0 15 10 L * ?" |
每月的最后一天的10:15觸發(fā) | |
"0 15 10 ? * 6L" |
每月最后一個周五的10:15觸發(fā) | |
"0 15 10 ? * 6L" |
每月最后一個周五的10:15觸發(fā) | |
"0 15 10 ? * 6L 2002-2005" |
2002年至2005年的每月最后一個周五的10:15觸發(fā) | |
"0 15 10 ? * 6#3" |
每月的第三個周五的10:15觸發(fā) |
1,研究spring webApplicationContext初始化。spring 如何初始化。
spring 有兩種方法,一個是ContextLoaderListener這個Listerner,另一個是ContextLoaderServlet這個Servlet,這兩個方法都是在web應(yīng)用啟動的時候來初始化WebApplicationContext,ContextLoader是一個工具類,用來初始化WebApplicationContext,其主要方法就是initWebApplicationContext,ContextLoader是把WebApplicationContext(XmlWebApplicationContext是默認(rèn)實現(xiàn)類)放在了ServletContext中,ServletContext也是一個“容器”,也是一個類似Map的結(jié)構(gòu),而WebApplicationContext在ServletContext中的KEY就是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,我們?nèi)绻褂肳ebApplicationContext則需要從ServletContext取出,Spring提供了一WebApplicationContextUtils類,可以方便的取出WebApplicationContext,只要把ServletContext傳入就可以了。
2,研究通過使用ApplicationContext對spring 進(jìn)行初始化。
初始化流程,在初始化的時候,新增一個加載servlet ,這個serlvet負(fù)責(zé)初始化。AppContextLoader 提供了初始化applicationContext的方法,
通過定義ClassPathXmlApplicationContext 來加載spring 配置文件。裝載配置文件。
并把裝載的ApplicationContext文件放在servletContext中作為全局變量來使用。在使用ClassPathXmlApplicationContext 則需要從ServletContext取出.
HttpClient httpClient = new HttpClient(); |
GetMethod getMethod = new GetMethod("http://www.ibm.com/"); |
//設(shè)置成了默認(rèn)的恢復(fù)策略,在發(fā)生異常時候?qū)⒆詣又卦?次,在這里你也可以設(shè)置成自定義的恢復(fù)策略 getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); //執(zhí)行g(shù)etMethod int statusCode = client.executeMethod(getMethod); if (statusCode != HttpStatus.SC_OK) { System.err.println("Method failed: " + getMethod.getStatusLine()); } |
byte[] responseBody = method.getResponseBody(); |
method.releaseConnection(); |
System.out.println(new String(responseBody)); |
下面是程序的完整代碼,這些代碼也可在附件中的test.GetSample中找到。
package test; import java.io.IOException; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpMethodParams; public class GetSample{ public static void main(String[] args) { //構(gòu)造HttpClient的實例 HttpClient httpClient = new HttpClient(); //創(chuàng)建GET方法的實例 GetMethod getMethod = new GetMethod("http://www.ibm.com"); //使用系統(tǒng)提供的默認(rèn)的恢復(fù)策略 getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); try { //執(zhí)行g(shù)etMethod int statusCode = httpClient.executeMethod(getMethod); if (statusCode != HttpStatus.SC_OK) { System.err.println("Method failed: " + getMethod.getStatusLine()); } //讀取內(nèi)容 byte[] responseBody = getMethod.getResponseBody(); //處理內(nèi)容 System.out.println(new String(responseBody)); } catch (HttpException e) { //發(fā)生致命的異常,可能是協(xié)議不對或者返回的內(nèi)容有問題 System.out.println("Please check your provided http address!"); e.printStackTrace(); } catch (IOException e) { //發(fā)生網(wǎng)絡(luò)異常 e.printStackTrace(); } finally { //釋放連接 getMethod.releaseConnection(); } } } |
根據(jù)RFC2616,對POST的解釋如下:POST方法用來向目的服務(wù)器發(fā)出請求,要求它接受被附在請求后的實體,并把它當(dāng)作請求隊列(Request-Line)中請求URI所指定資源的附加新子項。POST被設(shè)計成用統(tǒng)一的方法實現(xiàn)下列功能:
調(diào)用HttpClient中的PostMethod與GetMethod類似,除了設(shè)置PostMethod的實例與GetMethod有些不同之外,剩下的步驟都差不多。在下面的例子中,省去了與GetMethod相同的步驟,只說明與上面不同的地方,并以登錄清華大學(xué)BBS為例子進(jìn)行說明。
String url = "http://www.newsmth.net/bbslogin2.php"; PostMethod postMethod = new PostMethod(url); // 填入各個表單域的值 NameValuePair[] data = { new NameValuePair("id", "youUserName"), new NameValuePair("passwd", "yourPwd") }; // 將表單的值放入postMethod中 postMethod.setRequestBody(data); // 執(zhí)行postMethod int statusCode = httpClient.executeMethod(postMethod); // HttpClient對于要求接受后繼服務(wù)的請求,象POST和PUT等不能自動處理轉(zhuǎn)發(fā) // 301或者302 if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { // 從頭中取出轉(zhuǎn)向的地址 Header locationHeader = postMethod.getResponseHeader("location"); String location = null; if (locationHeader != null) { location = locationHeader.getValue(); System.out.println("The page was redirected to:" + location); } else { System.err.println("Location field value is null."); } return; } |
最近用到了HttpClient ,搜集的資料:
HttpClient 是 Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。本文首先介紹 HTTPClient,然后根據(jù)作者實際工作經(jīng)驗給出了一些常見問題的解決方法。
HTTP 協(xié)議可能是現(xiàn)在 Internet 上使用得最多、最重要的協(xié)議了,越來越多的 Java 應(yīng)用程序需要直接通過 HTTP 協(xié)議來訪問網(wǎng)絡(luò)資源。雖然在 JDK 的 java.net 包中已經(jīng)提供了訪問 HTTP 協(xié)議的基本功能,但是對于大部分應(yīng)用程序來說,JDK 庫本身提供的功能還不夠豐富和靈活。HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。HttpClient 已經(jīng)應(yīng)用在很多的項目中,比如 Apache Jakarta 上很著名的另外兩個開源項目 Cactus 和 HTMLUnit 都使用了 HttpClient,更多使用 HttpClient 的應(yīng)用可以參見http://wiki.apache.org/jakarta-httpclient/HttpClientPowered。HttpClient 項目非常活躍,使用的人還是非常多的。目前 HttpClient 版本是在 2005.10.11 發(fā)布的 3.0 RC4 。
![]() ![]() |
以下列出的是 HttpClient 提供的主要的功能,要知道更多詳細(xì)的功能可以參見 HttpClient 的主頁。
下面將逐一介紹怎樣使用這些功能。首先,我們必須安裝好 HttpClient。
![]() ![]() |
使用 HttpClient 需要以下 6 個步驟:
1. 創(chuàng)建 HttpClient 的實例
2. 創(chuàng)建某種連接方法的實例,在這里是 GetMethod。在 GetMethod 的構(gòu)造函數(shù)中傳入待連接的地址
3. 調(diào)用第一步中創(chuàng)建好的實例的 execute 方法來執(zhí)行第二步中創(chuàng)建好的 method 實例
4. 讀 response
5. 釋放連接。無論執(zhí)行方法是否成功,都必須釋放連接
6. 對得到后的內(nèi)容進(jìn)行處理