<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2008年7月7日 #

    java 數(shù)據(jù)庫(kù)緩沖池 使用c3p0

    c3p0很容易使用的開(kāi)源專業(yè)級(jí)jdbc數(shù)據(jù)庫(kù)緩沖池。
    它是sourceforge上的一個(gè)開(kāi)源項(xiàng)目,
    項(xiàng)目在
    http://sourceforge.net/projects/c3p0
    他的眾多特性這里就不一一介紹了。
    比較爽的一點(diǎn)就是
    當(dāng)Connection歸還緩沖池時(shí),c3p0會(huì)很小心的關(guān)閉
    這條連接打開(kāi)的Statement和ResultSet,免去了使用時(shí)
    自己動(dòng)手小心翼翼的關(guān)閉。

    c3p0使用非常簡(jiǎn)單,這里給一個(gè)例子

    package common.db;

    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.Properties;


    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import com.mchange.v2.c3p0.DataSources;

    public final class ConnectionManager {
    ?private static ConnectionManager instance;
    ?
    ?public ComboPooledDataSource ds;
    ?private static String c3p0Properties="c3p0.properties";
    ?
    ?private ConnectionManager() throws Exception {
    ??Properties p = new Properties();
    ??p.load(this.getClass().getResourceAsStream(c3p0Properties));
    ??ds = new ComboPooledDataSource();
    ?}
    ?
    ?public static final ConnectionManager getInstance() {
    ??if (instance == null) {
    ???try {
    ????instance = new ConnectionManager();
    ???} catch (Exception e) {
    ????e.printStackTrace();
    ???}
    ??}
    ??return instance;
    ?}
    ?
    ?public synchronized final Connection getConnection() {
    ??try {
    ???return ds.getConnection();
    ??} catch (SQLException e) {
    ???e.printStackTrace();
    ??}
    ??return null;
    ?}

    ?protected void finalize() throws Throwable {
    ??DataSources.destroy(ds);?//關(guān)閉datasource
    ??super.finalize();
    ?}
    ?
    }

    然后在ConnectionManager類的目錄下再創(chuàng)建一個(gè)配置文件c3p0.properties
    內(nèi)容如下:
    #db login parameters
    driverClass=com.mysql.jdbc.Driver
    jdbcUrl=jdbc:mysql://localhost/test?useUnicode=no&characterEncoding=GBK
    user=test
    password=test

    #pool parameters
    initialPoolSize=2
    maxPoolSize=5
    #maxIdleTime=10
    #idleConnectionTestPeriod=5
    autoCommitOnClose=true

    完整的配置文件參數(shù)參看c3p0的文檔

    使用connection時(shí)很簡(jiǎn)單
    Connection conn = ConnectionManager.getInstance().getConnection();
    ...
    最后 conn.close() 即可,

    posted @ 2008-10-23 10:24 金家寶 閱讀(4345) | 評(píng)論 (2)編輯 收藏

    JDBC也分2.0和3.0?

    如題。研究中...以前沒(méi)有注意過(guò)。

    posted @ 2008-10-23 10:10 金家寶 閱讀(293) | 評(píng)論 (0)編輯 收藏

    鯉魚(yú)論壇 研究筆記(未)

    2008.10.21第一天
    網(wǎng)站地址: http://www.liyunet.com/
    源碼下載: http://www.liyunet.com/bbs/download.jsp

    我主要是利用該論壇的簡(jiǎn)易性來(lái)研究JSP技術(shù),以及緩存技術(shù)。雖然說(shuō)目前大部分論壇應(yīng)用的都是主流框架技術(shù),但說(shuō)回來(lái),這些框架也只是對(duì)JSP等相關(guān)技術(shù)的一個(gè)封裝,而了解底部應(yīng)用及其原理更容易讓我理解主流框架的內(nèi)部原理機(jī)制。不至于讓框架把我們變成“傻子”。


    那就開(kāi)始吧
    首先,和某些大蝦一樣的習(xí)慣,我們從WEB-INF下的web.xml開(kāi)始,從以下代碼中可以發(fā)現(xiàn)隨著tomcat啟動(dòng)時(shí),自動(dòng)加載了InitServlet類。這是一個(gè)Servlet類。
    WEB-INF\web.xml部分代碼:
    1
    2<servlet-name>InitServlet</servlet-name>
    3????????<servlet-class>com.bcxy.servlet.InitServlet</servlet-class>
    4????????<load-on-startup>1</load-on-startup>
    5??????</servlet>
    6

    查看com.bcxy.servlet.InitServlet類,代碼很簡(jiǎn)單:
    開(kāi)始做了一個(gè)對(duì)此類日志(log4j)的綁定。接著通過(guò)SystemConfig取得了系統(tǒng)配置中的連接類型conntype(查看classes目錄下的SystemConfig.xml可知此變量是判斷使用連接池的類型0:3P0; 1:Proxool)。接著是初始化操作,記錄一些必要的啟動(dòng)信息(log4j)(其中做了本地地址和網(wǎng)絡(luò)訪問(wèn)地址的轉(zhuǎn)換)。
    用DBUtil.close測(cè)試連接池是否加載成功。
    最后是釋放類所做的必要操作。判斷使用的是哪一種連接池,然后關(guān)閉。這樣我們的第一個(gè)類就分析完畢。
    接著需要了解到
    SystemConfig類是加載SystemConfig.xml配置文件,并設(shè)定方法去讀取。其中有一定的類型轉(zhuǎn)換。

    此時(shí)似乎已經(jīng)找不到頭緒了。那這樣吧。我們就開(kāi)始訪問(wèn)我們自己搭建的論壇,從首頁(yè)開(kāi)始,也就是index.jsp頁(yè)面。
    瀏覽index.jsp代碼,由上向下理解每一個(gè)語(yǔ)句的含義(整體分體)。

    設(shè)定頁(yè)面編碼;導(dǎo)入IPLocalizer類(應(yīng)該是做IP顯示的工具類);插入INC/const.jsp頁(yè)(過(guò)后會(huì)有分析);設(shè)定stats變量數(shù)值(通過(guò)閱讀其他jsp頁(yè)面發(fā)現(xiàn),此變量的作用主要是在于在首頁(yè)顯示用戶狀態(tài)時(shí),兼并顯示當(dāng)前用戶做瀏覽的頁(yè)面:也就是stats的值,這樣我們可以在客戶可訪問(wèn)的范圍內(nèi)對(duì)stats變量進(jìn)行設(shè)置,就可以查看在線用戶的當(dāng)前行為);繼續(xù)插入INC/theme.jsp(估計(jì)是定制論壇模板的文件);<table>標(biāo)簽內(nèi)部就是連接到相關(guān)顯示數(shù)據(jù)信息的jsp頁(yè)面并附加了參數(shù)。其中的一些格式是通過(guò)上面引用文件中的變量設(shè)置,相對(duì)不難理解;論壇消息廣播部分,通過(guò)一個(gè)可執(zhí)行jsp頁(yè)面vector顯示在首頁(yè)頂部,當(dāng)中訪問(wèn)數(shù)據(jù)庫(kù)的細(xì)節(jié)需要進(jìn)一步研究代碼);接著是帖子的遍歷,也就是首頁(yè)最關(guān)鍵的部分,這里看起來(lái)不是由jsp頁(yè)面來(lái)負(fù)責(zé)獲取數(shù)據(jù),而是通過(guò)Forum類來(lái)獲取一些過(guò)濾之后的數(shù)據(jù):這里所說(shuō)的過(guò)濾是例如置頂帖子,最新帖子等有一些特殊標(biāo)記的數(shù)據(jù):;
    index.jsp的其他部分就都是大同小異了。都是通過(guò)一個(gè)遍歷來(lái)展現(xiàn)具有相同特性的數(shù)據(jù)。;大家需要注意一些關(guān)于頁(yè)面表現(xiàn)的而非java技術(shù)的部分,例如信息層的提示,和一些圖片連接。
    通過(guò)index.jsp的學(xué)習(xí),我們大概已經(jīng)了解了大部分jsp頁(yè)面代碼的表現(xiàn)形式和含義。當(dāng)然,一定要注意在這個(gè)過(guò)程中,參數(shù)傳遞、參數(shù)獲取的代碼部分,不要遺漏。除了一些我們可以看到的頁(yè)面之外,上面部分也講到了一些并不用于顯示給用戶的頁(yè)面,這里我們認(rèn)為它是可執(zhí)行頁(yè)面,也就是說(shuō)它對(duì)我們的數(shù)據(jù)和請(qǐng)求做了一些處理,或者說(shuō)把我們的請(qǐng)求轉(zhuǎn)交給了服務(wù)器(比如servlet)。

    預(yù)計(jì)晚上要研究一下有關(guān)數(shù)據(jù)庫(kù)方面的存取類JdbcWrapper以及連接獲取和釋放、數(shù)據(jù)查詢插入。
    2008.10.22
    大概昨天寫(xiě)的已經(jīng)忘的差不多了,那么我們還是從index.jsp文件開(kāi)始,前幾行沒(méi)有什么問(wèn)題,都是一些導(dǎo)入文件的標(biāo)簽,那么我們從SkinUtil.這個(gè)類入手。在查看SkinUtil類代碼的時(shí)候我們發(fā)現(xiàn)里面應(yīng)用了一些com\bcxy\bbs\util?包中類,其中含有三個(gè)工具類。(偷笑,看了文件大小,應(yīng)該代碼不多,我們看看里面都是什么)在開(kāi)始之前我們應(yīng)了解一下GCookie.java類的大概內(nèi)容和作用。看導(dǎo)入包我們可以大概了解一下此類的作用:對(duì)URL的編碼與解碼,產(chǎn)生和讀取Cookie,還有就是做一些日志記錄(log4j)。
    我們仔細(xì)閱讀后,了解到,其中有一個(gè)重載方法,也就是setCookie方法,根據(jù)不同的參數(shù),可以讓我們選擇直接賦予變量名和值的方法,或者是賦予變量名和值另外加上最大保存時(shí)間的方法。? 類中的另一個(gè)方法是獲取Cookie方法值。
    ParamUtil類也很簡(jiǎn)單,是取得字符串和 取得整數(shù)的重載方法,其中的參數(shù)決定是否有默認(rèn)值,是否需要轉(zhuǎn)碼。
    SysUtil類中根據(jù)SystemConfig類中的讀取方法讀取配置文件systemconfig.properties,按照里面的設(shè)置,來(lái)判斷是否對(duì)參數(shù)和數(shù)據(jù)庫(kù)讀取操作中的參數(shù)進(jìn)行編碼。其中還有一個(gè)方法是取得真實(shí)地址,當(dāng)然這些都是根據(jù)systemconfig.properties文件中配置而定的。
    BBSCconst.java類簡(jiǎn)單的設(shè)置了一些常量。作用是設(shè)置數(shù)據(jù)庫(kù)表名的時(shí)候加上systemconfig.properties中設(shè)置的前綴。
    回到SkinUtil.java類似乎看起來(lái)一些剛剛還陌生的類方法,顯得明朗。前面設(shè)置了一個(gè)Cookie的變量名并賦了值。

    ret?=?new?JdbcWrapper().doIntSearch(sql,?0);

    這里用到了新類,也就是我們昨天說(shuō)過(guò)的要了解的關(guān)于數(shù)據(jù)庫(kù)連接的類。也是今天要解決的重點(diǎn)。打開(kāi)JdbcWrapper類,查看代碼.(插一句,看代碼的時(shí)候,我覺(jué)得先看包名,了解大概要用到的類和方法,去設(shè)想這個(gè)類要實(shí)現(xiàn)的功能),yi一眼看來(lái),大概都熟悉,無(wú)非是連接數(shù)據(jù)庫(kù) 讀取,結(jié)果保存,異常,還有一些類似數(shù)組的HashMap還有遍歷用得Iterator。想想,大概就是數(shù)據(jù)層的一些基礎(chǔ)CRUD操作。但是其中有個(gè)類不是很熟悉,DatabaseMetaData類,查看sun公司的在線文檔,發(fā)現(xiàn)這是個(gè)接口而且方法奇多,文檔的第一句這么寫(xiě),

    Comprehensive?information?about?the?database?as?a?whole.?

    我也不能理解這句話包含了什么內(nèi)容。不管他,在程序中慢慢體會(huì)吧。JdbcWrapper這個(gè)類有點(diǎn)長(zhǎng),不過(guò),大部分方法都有類似的作用,也就是說(shuō)真正不同功能的代碼也只有幾分之一而已。我看的都想睡覺(jué)了。

    在網(wǎng)吧,因?yàn)椴槐悖入x開(kāi)咯
    今天還好,自己有一臺(tái)電腦,可以不限制時(shí)間。繼續(xù)工作....
    之前研究JdbcWrapper類的時(shí)候有一個(gè)小小的疑問(wèn)。如下

    ?

    ?1?????//######這里有一點(diǎn)不明白,為什么要判斷getAutoClose()
    ?2????/*
    ?3?????*?當(dāng)需要事務(wù)支持時(shí),需要設(shè)置autoClose=false,那就等到事務(wù)提交時(shí)再關(guān)閉數(shù)據(jù)庫(kù)連接。
    ?4?????*?*/

    ?5????public?void?closeConnection()?{
    ?6????????if?(getAutoClose())?{
    ?7????????????DBUtil.close(pstmt,?con);
    ?8????????}

    ?9????}

    10

    今天看群里鯉魚(yú)回答內(nèi)容如下:

    當(dāng)需要事務(wù)支持時(shí),需要設(shè)置autoClose=false,那就等到事務(wù)提交時(shí)再關(guān)閉數(shù)據(jù)庫(kù)連接。


    一時(shí)還沒(méi)有理解開(kāi)來(lái)。
    看過(guò)來(lái)看過(guò)去,JdbcWrapper類對(duì)我來(lái)講還是有一部分難以理解。索性不去管它,等在下面的代碼中出現(xiàn)時(shí),反復(fù)查閱應(yīng)該會(huì)有更多的收獲。

    posted @ 2008-10-21 11:47 金家寶 閱讀(360) | 評(píng)論 (0)編輯 收藏

    關(guān)于正則表達(dá)式

    *匹配除了換行之外的所有字符

    合法IP的正則表達(dá)式 ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

    \s匹配任意的空白符、(空格、制表符、換行符、中文全角空格)
    \w匹配字母或數(shù)字或下劃線或漢字

    表1.常用的元字符
    代碼說(shuō)明
    .匹配除換行符以外的任意字符
    \w匹配字母或數(shù)字或下劃線或漢字
    \s匹配任意的空白符
    \d匹配數(shù)字
    \b匹配單詞的開(kāi)始或結(jié)束
    ^匹配字符串的開(kāi)始
    $匹配字符串的結(jié)束


    表2.常用的限定符
    代碼/語(yǔ)法說(shuō)明
    *重復(fù)零次或更多次
    +重復(fù)一次或更多次
    ?重復(fù)零次或一次
    {n}重復(fù)n次
    {n,}重復(fù)n次或更多次
    {n,m}重復(fù)n到m次


    后向引用

    使用小括號(hào)指定一個(gè)子表達(dá)式后,匹配這個(gè)子表達(dá)式的文本(也就是此分組捕獲的內(nèi)容)可以在表達(dá)式或其它程序中作進(jìn)一步的處理。默認(rèn)情況下,每個(gè)分組會(huì)自動(dòng)擁有一個(gè)組號(hào),規(guī)則是:從左向右,以分組的左括號(hào)為標(biāo)志,第一個(gè)出現(xiàn)的分組的組號(hào)為1,第二個(gè)為2,以此類推。

    后向引用用于重復(fù)搜索前面某個(gè)分組匹配的文本。例如,\1代表分組1匹配的文本。難以理解?請(qǐng)看示例:

    \b(\w+)\b\s+\1\b可以用來(lái)匹配重復(fù)的單詞,像go go, 或者kitty kitty。這個(gè)表達(dá)式首先是一個(gè)單詞,也就是單詞開(kāi)始處和結(jié)束處之間的多于一個(gè)的字母或數(shù)字(\b(\w+)\b),這個(gè)單詞會(huì)被捕獲到編號(hào)為1的分組中,然后是1個(gè)或幾個(gè)空白符(\s+),最后是分組1中捕獲的內(nèi)容(也就是前面匹配的那個(gè)單詞)(\1)。

    你也可以自己指定子表達(dá)式的組名。要指定一個(gè)子表達(dá)式的組名,請(qǐng)使用這樣的語(yǔ)法:(?<Word>\w+)(或者把尖括號(hào)換成'也行:(?'Word'\w+)),這樣就把\w+的組名指定為Word了。要反向引用這個(gè)分組捕獲的內(nèi)容,你可以使用\k<Word>,所以上一個(gè)例子也可以寫(xiě)成這樣:\b(?<Word>\w+)\b\s+\k<Word>\b

    使用小括號(hào)的時(shí)候,還有很多特定用途的語(yǔ)法。下面列出了最常用的一些:

    表4.常用分組語(yǔ)法
    分類代碼/語(yǔ)法說(shuō)明
    捕獲(exp)匹配exp,并捕獲文本到自動(dòng)命名的組里
    (?<name>exp)匹配exp,并捕獲文本到名稱為name的組里,也可以寫(xiě)成(?'name'exp)
    (?:exp)匹配exp,不捕獲匹配的文本,也不給此分組分配組號(hào)
    零寬斷言(?=exp)匹配exp前面的位置
    (?<=exp)匹配exp后面的位置
    (?!exp)匹配后面跟的不是exp的位置
    (?<!exp)匹配前面不是exp的位置
    注釋(?#comment)這種類型的分組不對(duì)正則表達(dá)式的處理產(chǎn)生任何影響,用于提供注釋讓人閱讀


    表5.懶惰限定符
    代碼/語(yǔ)法說(shuō)明
    *?重復(fù)任意次,但盡可能少重復(fù)
    +?重復(fù)1次或更多次,但盡可能少重復(fù)
    ??重復(fù)0次或1次,但盡可能少重復(fù)
    {n,m}?重復(fù)n到m次,但盡可能少重復(fù)
    {n,}?重復(fù)n次以上,但盡可能少重復(fù)


    表6.常用的處理選項(xiàng)
    名稱說(shuō)明
    IgnoreCase(忽略大小寫(xiě))匹配時(shí)不區(qū)分大小寫(xiě)。
    Multiline(多行模式)更改^$的含義,使它們分別在任意一行的行首和行尾匹配,而不僅僅在整個(gè)字符串的開(kāi)頭和結(jié)尾匹配。(在此模式下,$的精確含意是:匹配\n之前的位置以及字符串結(jié)束前的位置.)
    Singleline(單行模式)更改.的含義,使它與每一個(gè)字符匹配(包括換行符\n)。
    IgnorePatternWhitespace(忽略空白)忽略表達(dá)式中的非轉(zhuǎn)義空白并啟用由#標(biāo)記的注釋。
    RightToLeft(從右向左查找)匹配從右向左而不是從左向右進(jìn)行。
    ExplicitCapture(顯式捕獲)僅捕獲已被顯式命名的組。
    ECMAScript(JavaScript兼容模式)使表達(dá)式的行為與它在JavaScript里的行為一致。
    表7.尚未詳細(xì)討論的語(yǔ)法
    代碼/語(yǔ)法說(shuō)明
    \a報(bào)警字符(打印它的效果是電腦嘀一聲)
    \b通常是單詞分界位置,但如果在字符類里使用代表退格
    \t制表符,Tab
    \r回車
    \v豎向制表符
    \f換頁(yè)符
    \n換行符
    \eEscape
    \0nnASCII代碼中八進(jìn)制代碼為nn的字符
    \xnnASCII代碼中十六進(jìn)制代碼為nn的字符
    \unnnnUnicode代碼中十六進(jìn)制代碼為nnnn的字符
    \cNASCII控制字符。比如\cC代表Ctrl+C
    \A字符串開(kāi)頭(類似^,但不受處理多行選項(xiàng)的影響)
    \Z字符串結(jié)尾或行尾(不受處理多行選項(xiàng)的影響)
    \z字符串結(jié)尾(類似$,但不受處理多行選項(xiàng)的影響)
    \G當(dāng)前搜索的開(kāi)頭
    \p{name}Unicode中命名為name的字符類,例如\p{IsGreek}
    (?>exp)貪婪子表達(dá)式
    (?<x>-<y>exp)平衡組
    (?im-nsx:exp)在子表達(dá)式exp中改變處理選項(xiàng)
    (?im-nsx)為表達(dá)式后面的部分改變處理選項(xiàng)
    (?(exp)yes|no)把exp當(dāng)作零寬正向先行斷言,如果在這個(gè)位置能匹配,使用yes作為此組的表達(dá)式;否則使用no
    (?(exp)yes)同上,只是使用空表達(dá)式作為no
    (?(name)yes|no)如果命名為name的組捕獲到了內(nèi)容,使用yes作為表達(dá)式;否則使用no
    (?(name)yes)同上,只是使用空表達(dá)式作為no

    posted @ 2008-10-17 11:10 金家寶 閱讀(321) | 評(píng)論 (1)編輯 收藏

    Lucene倒排索引原理(轉(zhuǎn))

    Lucene是一個(gè)高性能的java全文檢索工具包,它使用的是倒排文件索引結(jié)構(gòu)。該結(jié)構(gòu)及相應(yīng)的生成算法如下:

    0)設(shè)有兩篇文章1和2
    文章1的內(nèi)容為:Tom?lives?in?Guangzhou,I?live?in?Guangzhou?too.
    文章2的內(nèi)容為:He?once?lived?in?Shanghai.

    1)由于lucene是基于關(guān)鍵詞索引和查詢的,首先我們要取得這兩篇文章的關(guān)鍵詞,通常我們需要如下處理措施
    a.我們現(xiàn)在有的是文章內(nèi)容,即一個(gè)字符串,我們先要找出字符串中的所有單詞,即分詞。英文單詞由于用空格分隔,比較好處理。中文單詞間是連在一起的需要特殊的分詞處理。
    b.文章中的”in”,?“once”?“too”等詞沒(méi)有什么實(shí)際意義,中文中的“的”“是”等字通常也無(wú)具體含義,這些不代表概念的詞可以過(guò)濾掉
    c.用戶通常希望查“He”時(shí)能把含“he”,“HE”的文章也找出來(lái),所以所有單詞需要統(tǒng)一大小寫(xiě)。
    d.用戶通常希望查“l(fā)ive”時(shí)能把含“l(fā)ives”,“l(fā)ived”的文章也找出來(lái),所以需要把“l(fā)ives”,“l(fā)ived”還原成“l(fā)ive”
    e.文章中的標(biāo)點(diǎn)符號(hào)通常不表示某種概念,也可以過(guò)濾掉
    在lucene中以上措施由Analyzer類完成

    經(jīng)過(guò)上面處理后
    ????文章1的所有關(guān)鍵詞為:[tom]?[live]?[guangzhou]?[i]?[live]?[guangzhou]
    ????文章2的所有關(guān)鍵詞為:[he]?[live]?[shanghai]

    2)?有了關(guān)鍵詞后,我們就可以建立倒排索引了。上面的對(duì)應(yīng)關(guān)系是:“文章號(hào)”對(duì)“文章中所有關(guān)鍵詞”。倒排索引把這個(gè)關(guān)系倒過(guò)來(lái),變成:“關(guān)鍵詞”對(duì)“擁有該關(guān)鍵詞的所有文章號(hào)”。文章1,2經(jīng)過(guò)倒排后變成
    關(guān)鍵詞???文章號(hào)
    guangzhou??1
    he?????????2
    i???????????1
    live???????1,2
    shanghai???2
    tom?????????1

    通常僅知道關(guān)鍵詞在哪些文章中出現(xiàn)還不夠,我們還需要知道關(guān)鍵詞在文章中出現(xiàn)次數(shù)和出現(xiàn)的位置,通常有兩種位置:a)字符位置,即記錄該詞是文章中第幾個(gè)字符(優(yōu)點(diǎn)是關(guān)鍵詞亮顯時(shí)定位快);b)關(guān)鍵詞位置,即記錄該詞是文章中第幾個(gè)關(guān)鍵詞(優(yōu)點(diǎn)是節(jié)約索引空間、詞組(phase)查詢快),lucene中記錄的就是這種位置。

    加上“出現(xiàn)頻率”和“出現(xiàn)位置”信息后,我們的索引結(jié)構(gòu)變?yōu)椋?br />關(guān)鍵詞???文章號(hào)[出現(xiàn)頻率]???出現(xiàn)位置
    guangzhou?1[2]???????????????3,6
    he???????2[1]???????????????1
    i?????????1[1]???????????????4
    live??????1[2],2[1]???????????2,5,2
    shanghai??2[1]???????????????3
    tom??????1[1]???????????????1

    以live 這行為例我們說(shuō)明一下該結(jié)構(gòu):live在文章1中出現(xiàn)了2次,文章2中出現(xiàn)了一次,它的出現(xiàn)位置為“2,5,2”這表示什么呢?我們需要結(jié)合文章號(hào)和出現(xiàn)頻率來(lái)分析,文章1中出現(xiàn)了2次,那么“2,5”就表示live在文章1中出現(xiàn)的兩個(gè)位置,文章2中出現(xiàn)了一次,剩下的“2”就表示live是文章2中第 2個(gè)關(guān)鍵字。
    ????
    以上就是lucene索引結(jié)構(gòu)中最核心的部分。我們注意到關(guān)鍵字是按字符順序排列的(lucene沒(méi)有使用B樹(shù)結(jié)構(gòu)),因此lucene可以用二元搜索算法快速定位關(guān)鍵詞。
    ????
    實(shí)現(xiàn)時(shí)?lucene將上面三列分別作為詞典文件(Term?Dictionary)、頻率文件(frequencies)、位置文件 (positions)保存。其中詞典文件不僅保存有每個(gè)關(guān)鍵詞,還保留了指向頻率文件和位置文件的指針,通過(guò)指針可以找到該關(guān)鍵字的頻率信息和位置信息。

    ????Lucene中使用了field的概念,用于表達(dá)信息所在位置(如標(biāo)題中,文章中,url中),在建索引中,該field信息也記錄在詞典文件中,每個(gè)關(guān)鍵詞都有一個(gè)field信息(因?yàn)槊總€(gè)關(guān)鍵字一定屬于一個(gè)或多個(gè)field)。

    ???? 為了減小索引文件的大小,Lucene對(duì)索引還使用了壓縮技術(shù)。首先,對(duì)詞典文件中的關(guān)鍵詞進(jìn)行了壓縮,關(guān)鍵詞壓縮為<前綴長(zhǎng)度,后綴>,例如:當(dāng)前詞為“阿拉伯語(yǔ)”,上一個(gè)詞為“阿拉伯”,那么“阿拉伯語(yǔ)”壓縮為<3,語(yǔ)>。其次大量用到的是對(duì)數(shù)字的壓縮,數(shù)字只保存與上一個(gè)值的差值(這樣可以減小數(shù)字的長(zhǎng)度,進(jìn)而減少保存該數(shù)字需要的字節(jié)數(shù))。例如當(dāng)前文章號(hào)是16389(不壓縮要用3個(gè)字節(jié)保存),上一文章號(hào)是16382,壓縮后保存7(只用一個(gè)字節(jié))。
    ????
    ????下面我們可以通過(guò)對(duì)該索引的查詢來(lái)解釋一下為什么要建立索引。
    假設(shè)要查詢單詞?“l(fā)ive”,lucene先對(duì)詞典二元查找、找到該詞,通過(guò)指向頻率文件的指針讀出所有文章號(hào),然后返回結(jié)果。詞典通常非常小,因而,整個(gè)過(guò)程的時(shí)間是毫秒級(jí)的。
    而用普通的順序匹配算法,不建索引,而是對(duì)所有文章的內(nèi)容進(jìn)行字符串匹配,這個(gè)過(guò)程將會(huì)相當(dāng)緩慢,當(dāng)文章數(shù)目很大時(shí),時(shí)間往往是無(wú)法忍受的。

    posted @ 2008-10-17 09:43 金家寶 閱讀(2835) | 評(píng)論 (1)編輯 收藏

    struts2標(biāo)簽

    ?

    一、
    寫(xiě)jsp頁(yè)面的時(shí)候,在struts2中,用的是s標(biāo)記,先引入標(biāo)記:
    <%@ taglib prefix="s" uri="/struts-tags"%>
    二、
    struts2的標(biāo)簽和1是完全不同的。
    struts2的標(biāo)簽分為兩大類:非UI標(biāo)志和UI標(biāo)志 struts1 將標(biāo)志庫(kù)按功能分成HTML、Tiles、Logic和Bean等幾部分
    下面就介紹strut2的具體標(biāo)簽:
    1、UI
    UI標(biāo)志又可以分為表單UI和非表單UI兩部分。表單UI部分基本與Struts 1.x相同,都是對(duì)HTML表單元素的包裝。不過(guò),Struts 2.0加了幾個(gè)我們經(jīng)常在項(xiàng)目中用到的控件如:datepicker、doubleselect、timepicker、optiontransferselect等。因?yàn)檫@些標(biāo)志很多都經(jīng)常用到,而且參數(shù)也很多,要在一篇文章詳細(xì)說(shuō)明并非易事。
    下面主要是ui標(biāo)簽的一些用法
    form:
    <s:form action="exampleSubmit" method="post" enctype="multipart/form-data">
    <s:submit />
    ??? <s:reset />

    </s:form>可以上傳文件的form。
    textfield:
    <s:textfield
    ??????????? label="姓名:"
    ??????????? name="name"
    ??????????? tooltip="Enter your Name here" />
    datepicker:
    <s:datepicker
    ??????????? tooltip="Select Your Birthday"
    ??????????? label="生日"
    ??????????? name="birthday" />
    textarea:
    <s:textarea
    ??????????? tooltip="Enter your remart"
    ??????????? label="備注"
    ??????????? name="remart"
    ??????????? cols="20"
    ??????????? rows="3"/>
    select:
    <s:select
    ??????????? tooltip="Choose user_type"
    ??????????? label=""
    ??????????? list="#{'free':'免費(fèi)','vip':'收費(fèi)'}" value="#{'free':'免費(fèi)'}"??
    ?????????? name="bean.user_type"
    ??????????? emptyOption="true"
    ??????????? headerKey="None"
    ??????????? headerValue="None"/>
    <s:select
    ??????????? tooltip="Choose user_type"
    ??????????? label=""
    ??????????? list="#{'free':'免費(fèi)','vip':'收費(fèi)'}" value="#{'free':'免費(fèi)'}"??
    ?????????? name="bean.user_type"
    ??????????? emptyOption="true"
    ??????????? headerKey="None"
    ??????????? headerValue="None"/>
    <s:select
    list="venderList"
    listKey="id"
    listValue="name"
    value="%{profile.companyName}"
    name="companyName" cssClass="sel_style_w_180"/>??
    挺好用的
    checkboxlist:
    <s:checkboxlist
    ??????????? tooltip="Choose your Friends"
    ??????????? label="朋友"
    ??????????? list="{'Patrick', 'Jason', 'Jay', 'Toby', 'Rene'}"
    ??????????? name="friends"/>
    checkbox:
    ?? <s:checkbox
    ??????????? tooltip="Confirmed that your are Over 18"
    ??????????? label="年齡"
    ??????????? name="legalAge"
    ??????????? value="18"/>
    file:
    ?? <s:file
    ??????????? tooltip="Upload Your Picture"
    ??????????? label="Picture"
    ??????????? name="picture" />
    a:
    <s:a href="getP.jsp">超鏈接提交</s:a>
    date :
    <s:date name="ad_end_time" format="yyyy-MM-dd"/>


    2、非UI
    if、elseif和else 描述:
    執(zhí)行基本的條件流轉(zhuǎn)。
    參數(shù):
    名稱必需默認(rèn)類型描述備注test是Boolean決定標(biāo)志里內(nèi)容是否顯示的表達(dá)式else標(biāo)志沒(méi)有這個(gè)參數(shù)id否Object/String用來(lái)標(biāo)識(shí)元素的id。在UI和表單中為HTML的id屬性 例子:
    <%@ page c %>
    <%@ taglib prefix="s" uri="/struts-tags" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    ??? <head>
    ??????? <title>Condition Flow</title>
    ??? </head>
    ??? <body>
    ??????? <h3>Condition Flow</h3>????????????
    ??????? <!--
    ??????????? 這里有點(diǎn)小技巧:
    ??????????? 本來(lái)可以用#parameters.name[0]來(lái)獲得,請(qǐng)求中name的值。但是,在我實(shí)現(xiàn)include例子時(shí),
    ??????????? 無(wú)論我用param標(biāo)志給name賦任何值,#parameters里面不會(huì)含有任何值,所以#parameters.name也為空值。
    ????????????
    ??????????? 其原因?yàn)椋?
    ??????????? 當(dāng)使用include標(biāo)志時(shí),被包含的頁(yè)面(included)里#parameters拿到的是包含頁(yè)面里的請(qǐng)求參數(shù)。
    ????????????
    ??????????? 因此,這里必須手工調(diào)用request.getParameter("name")。
    ??????? -->
    ??? <s:iterator value="linkList" status="bean">
    ?? <tr>
    ??? <td class="data_tab_tdcl">
    ???? <s:property value="#bean.Index+1" />??? </td>
    ??? <td class="data_tab_tdcl"><s:property value="link_title" /></td>
    ??? <td class="data_tab_tdcl"><s:property value="link_url" /></td>
    ??? <td class="data_tab_tdcl">
    ??? <s:if test="link_type == 1">
    ?????????????????? 文字
    ??????????????? </s:if>
    ??????????????? <s:elseif test="link_type == 2">
    ?????????????????? 圖片
    ??????????????? </s:elseif>
    ???????????????? <s:else>
    ???????????????? -----
    ?????????????? </s:else>???
    ??? </td>

    ???
    ??? </body>
    </html>
    例1 condition.jsp
    iterator 描述:
    用于遍歷集合(java.util.Collection)或枚舉值(java.util.Iterator)。
    參數(shù):
    名稱必需默認(rèn)類型描述status否String如果設(shè)置此參數(shù),一個(gè)IteratorStatus的實(shí)例將會(huì)壓入每個(gè)遍歷的堆棧value否Object/String要遍歷的可枚舉的(iteratable)數(shù)據(jù)源,或者將放入新列表(List)的對(duì)象id否Object/String用來(lái)標(biāo)識(shí)元素的id。在UI和表單中為HTML的id屬性 例子:
    <%@ page c %>
    <%@ page import="java.util.List" %>
    <%@ page import="java.util.ArrayList" %>
    <%@ taglib prefix="s" uri="/struts-tags" %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <%
    ??? List list = new ArrayList();
    ??? list.add("Max");
    ??? list.add("Scott");
    ??? list.add("Jeffry");
    ??? list.add("Joe");
    ??? list.add("Kelvin");
    ??? request.setAttribute("names", list);
    %>
    <html>
    ??? <head>
    ??????? <title>Iterator</title>
    ??? </head>
    ??? <body>
    ??????? <h3>Names: </h3>
    ??????? <!--
    ??????????? 1、此處的空property元素用于獲得當(dāng)前iterator的值
    ??????????? 2、status被設(shè)成stuts,在iterator的里面就可以通過(guò)#stuts取得IteratorStatus的對(duì)象。IteratorStatus類包含當(dāng)前序號(hào)信息,如是否第一個(gè)或最后一個(gè),是否為奇數(shù)序號(hào)。這些信息在我們做格式化的時(shí)候,顯得非常有用。
    ??????? -->
    ??????? <ol>
    ??????????? <s:iterator value="#request.names" status="stuts">????????????????
    ??????????????? <s:if test="#stuts.odd == true">
    ??????????????????? <li>White <s:property /></li>
    ??????????????? </s:if>
    ??????????????? <s:else>
    ??????????????????? <li style="background-color:gray"><s:property /></li>
    ??????????????? </s:else>
    ??????????? </s:iterator>
    ??????? </ol>
    ??? </body>
    </html>

    posted @ 2008-10-13 15:46 金家寶 閱讀(521) | 評(píng)論 (1)編輯 收藏

    Java筆試題(部分)

         摘要: EJB 方面 ? 94 、 EJB2.0 ...  閱讀全文

    posted @ 2008-10-09 11:56 金家寶 閱讀(720) | 評(píng)論 (0)編輯 收藏

    安裝WinCVS時(shí)Python不可用的問(wèn)題

    在我裝完Wincvs之后,提示我沒(méi)有安裝python,但后來(lái)我又裝了python2.4,可Wincvs還是說(shuō)配置不對(duì).到底要怎么配置python呢?期待著您的回復(fù),謝謝你了!
    ???
    TCL or Python are not available, shell is disabled。
    有的網(wǎng)友說(shuō)是版本的問(wèn)題,我今天安裝時(shí)也是一樣,裝了好三四個(gè)版本,都一樣,最后在CSDN上找到了答案。

    解決辦法:

    在admin-〉Preferences->wincvs中有關(guān)于python的設(shè)置, ?
    ? 其中python是指你的python虛擬機(jī)的位置,一般是python2X.dll的位置。在你來(lái)說(shuō)就是python24.dll的位置,一般這個(gè)文件會(huì)在你的系統(tǒng)文件中找到。 ?
    ? Tcl則一般會(huì)在python文件架的dlls子文件架中找到,一般名稱為tclxx.dll,在你大概就是tcl84.dll。如果是安裝python2.3版本的話,會(huì)自動(dòng)找到,不需要設(shè)置。

    設(shè)置好了,WinCVS輸出窗口:

    Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on win32Tk is available, Tk-macros are enabledTCL is available, shell is enabled : help (select and press enter)

    posted @ 2008-09-21 08:52 金家寶 閱讀(3613) | 評(píng)論 (1)編輯 收藏

    [設(shè)計(jì)模式]jive中的[abstract Factory]

      AbstractFactory模式和可擴(kuò)展性
      假如要實(shí)現(xiàn)較好的可擴(kuò)展性,AbstractFactory模式確實(shí)是一件利器。如上面所說(shuō),假如要?jiǎng)?chuàng)建的Forum接口的不同實(shí)現(xiàn),而又不想更改代碼的話,就需要用到抽象工廠了。再Jive中,AuthorizationFactory類是一個(gè)抽象類,用來(lái)創(chuàng)建Authorization對(duì)象。這是一個(gè)抽象工廠,可以通過(guò)不同的子類來(lái)創(chuàng)建不同的Authorization對(duì)象。這個(gè)工廠的實(shí)現(xiàn)方法是:
      
      在AuthorizationFactory中使用一個(gè)private static變量factory,用來(lái)引用具體的抽象工廠的實(shí)例:
      private static AuthorizationFactory factory = null;
      
      用一個(gè)private static的String,來(lái)指明具體的抽象工廠的子類類名:
      private static String className ="com.coolservlets.forum.database.DbAuthorizationFactory";
      
      然后是用一個(gè)private static的loadAuthorizationFactory方法來(lái)給這個(gè)factory變量賦值,生成具體的抽象工廠類:
      
        private static void loadAuthorizationFactory() {
          if (factory == null) {
            synchronized(className) {
              if (factory == null) {
                String classNameProp = PropertyManager.getProperty(
                  "AuthorizationFactory.className"
                );
                if (classNameProp != null) {
                  className = classNameProp;
                }
                try {
                  Class c = Class.forName(className);
                  factory = (AuthorizationFactory)c.newInstance();
                }
                catch (Exception e) {
                  System.err.println("Exception loading class: " + e);
                  e.printStackTrace();
                }
              }
            }
          }
      }
      
      在static的getAuthorization方法返回一個(gè)Authorization的過(guò)程中,先初始化工廠類factory變量,然后用factory的createAuthorization方法來(lái)創(chuàng)建:
      
        public static Authorization getAuthorization(String username,
            String passWord) throws UnauthorizedException
        {
          loadAuthorizationFactory();
          return factory.createAuthorization(username, password);
      }
      
      不同的子類有不同的createAuthorization方法的實(shí)現(xiàn)。比如在DbAuthorizationFactory這個(gè)AuthorizationFactory的數(shù)據(jù)庫(kù)實(shí)現(xiàn)子類中,createAuthorization方法是這樣實(shí)現(xiàn)的:
      
        public Authorization createAuthorization(String username, String password)
            throws UnauthorizedException
        {
          if (username == null password == null) {
            throw new UnauthorizedException();
          }
          password = StringUtils.hash(password);
          int userID = 0;
          Connection con = null;
          PreparedStatement pstmt = null;
          try {
            con = DbConnectionManager.getConnection();
            pstmt = con.prepareStatement(AUTHORIZE);
            pstmt.setString(1, username);
            pstmt.setString(2, password);
      
            ResultSet rs = pstmt.executeQuery();
            if (!rs.next()) {
              throw new UnauthorizedException();
            }
            userID = rs.getInt(1);
          }
          catch( SQLException sqle ) {
            System.err.println("Exception in DbAuthorizationFactory:" + sqle);
            sqle.printStackTrace();
            throw new UnauthorizedException();
          }
          finally {
            try { pstmt.close(); }
            catch (Exception e) { e.printStackTrace(); }
            try { con.close();  }
            catch (Exception e) { e.printStackTrace(); }
          }
          return new DbAuthorization(userID);
        }
      
      在這個(gè)類中,可以看到抽象類和具體的子類之間的關(guān)系,它們是如何協(xié)作的,又是如何劃分抽象方法和非抽象方法的,這都是值得注重的地方。一般的,抽象方法需要子類來(lái)實(shí)現(xiàn),而抽象類中的非抽象方法應(yīng)該所有子類所能夠共享的,或者可是說(shuō),是定義在抽象方法之上的較高層的方法。這確實(shí)是一個(gè)抽象工廠的好例子!雖然實(shí)現(xiàn)的方法已經(jīng)和GOF中給出的實(shí)現(xiàn)相差較遠(yuǎn)了,但思想沒(méi)變,這兒的實(shí)現(xiàn),也確實(shí)是要巧妙的些。
      
      還有就是靜態(tài)方法的使用,使得這個(gè)類看起來(lái)有些Singleton的意味。這使得對(duì)于AbstractFactory的創(chuàng)建變得簡(jiǎn)單。
      
      在AuthorizationFactory中定義的其它方法,涉及到具體的如何創(chuàng)建Authorization,都是作為abstract方法出現(xiàn),具體實(shí)現(xiàn)留給子類來(lái)完成。
      
      這樣,在需要生成一個(gè)Authorization的時(shí)候,只需要調(diào)用AuthorizationFactory的靜態(tài)方法getAuthorization就可以了,由子類實(shí)現(xiàn)了具體的細(xì)節(jié)。
      
      其它的,如同上面講到的,在創(chuàng)建Forum的時(shí)候用的ForumFactory,具有同上面一樣的實(shí)現(xiàn),這就是模式之所以稱為模式的所在了。
    資料引用:http://www.knowsky.com/365144.html

    posted @ 2008-09-16 15:57 金家寶 閱讀(262) | 評(píng)論 (0)編輯 收藏

    題目: IOC 后臺(tái)機(jī)制學(xué)習(xí)

    ?
    題目: IOC 后臺(tái)機(jī)制學(xué)習(xí)
    給定:
    配置文件 config.txt, 文件內(nèi)容
    className = test.JavaBean1
    field = username
    value = ABC

    該文件中的三個(gè)值會(huì)隨時(shí)可能變化, 唯一不變的是 className 指定的都是一個(gè) JavaBean(為了簡(jiǎn)化, 我們假定里面已經(jīng)有一個(gè) username 屬性, 例如:

    class JavaBeanxxxx {
    ?? ?private String username;

    ?? ?public String getUsername() {
    ?? ??? ?return username;
    ?? ?}

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

    要求: 寫(xiě)一段代碼, 讀取配置文件 config.txt, 然后實(shí)現(xiàn)把 className 指定的 JavaBean 類加載(注意這個(gè)類名是可以修改的, 可配置的), 然后生成一個(gè)實(shí)例,
    并把配置文件中field字段指定的值作為這個(gè)實(shí)例的屬性名(這里是username)所對(duì)應(yīng)的值設(shè)置為 ABC(字符串), 并且要讀出最后設(shè)置的值.

    此題已經(jīng)被 TigerTian 解答出來(lái), 歡迎學(xué)習(xí), 也感謝 TigerTian:
    package?com.gcoresoft.ioc;

    import?java.io.*;
    import?java.lang.reflect.*;
    import?java.util.*;
    import?java.beans.*;

    public?class?IOCStudy?{
    ????
    ????
    //Load?the?properties?file
    ????private?Properties?prop=new?Properties();
    ????
    ????
    public?void?loadPropFile(String?filename)
    ????{
    ????????
    try
    ????????{
    ????????????FileInputStream?fin
    =new?FileInputStream(filename);
    ????????????prop.load(fin);
    ????????????fin.close();
    ????????}
    catch(Exception?e){
    ????????????System.out.println(e.toString());
    ????????}
    ????}
    ????
    ????
    private?String?getValueByName(String?Name)
    ????{
    ????????
    return?prop.getProperty(Name);
    ????}
    ????
    ????
    public?static?void?main(String[]?args)
    ????{
    ????????IOCStudy?ioc
    =new?IOCStudy();
    ????????ioc.loadPropFile(
    "E:\\Work\\GetInIOC\\src\\com\\gcoresoft\\ioc\\Config.txt");
    ????????
    try
    ????????{
    ????????????Class?bean
    =Class.forName(ioc.getValueByName("className"));
    ????????????
    try?{
    ????????????????java.beans.BeanInfo?info
    =java.beans.Introspector.getBeanInfo(bean);
    ????????????????java.beans.PropertyDescriptor?pd[]
    =info.getPropertyDescriptors();
    ????????????????
    try?{
    ????????????????????Method?mSet
    =null,mRead=null;
    ????????????????????Object?obj
    =bean.newInstance();
    ????????????????????
    for(int?i=0;i<pd.length;i++)
    ????????????????????????
    if(pd[i].getName().equalsIgnoreCase(ioc.getValueByName("field")))
    ????????????????????????{
    ????????????????????????????mSet
    =pd[i].getWriteMethod();
    ????????????????????????????mRead
    =pd[i].getReadMethod();????????????????????????????
    ????????????????????????}
    ????????????????????
    try?{
    ????????????????????????mSet.invoke(obj,?ioc.getValueByName(
    "value"));
    ????????????????????????String?str
    =(String)mRead.invoke(obj,?null);
    ????????????????????????System.out.println(str);
    ????????????????????}?
    catch?(IllegalArgumentException?e)?{
    ????????????????????????
    //?TODO?Auto-generated?catch?block
    ????????????????????????e.printStackTrace();
    ????????????????????}?
    catch?(InvocationTargetException?e)?{
    ????????????????????????
    //?TODO?Auto-generated?catch?block
    ????????????????????????e.printStackTrace();
    ????????????????????}
    ????????????????}?
    catch?(InstantiationException?e)?{
    ????????????????????
    //?TODO?Auto-generated?catch?block
    ????????????????????e.printStackTrace();
    ????????????????}?
    catch?(IllegalAccessException?e)?{
    ????????????????????
    //?TODO?Auto-generated?catch?block
    ????????????????????e.printStackTrace();
    ????????????????}

    ????????????????
    ????????????}?
    catch?(IntrospectionException?e)?{
    ????????????????
    //?TODO?Auto-generated?catch?block
    ????????????????e.printStackTrace();
    ????????????}
    ????????????
    ????????????
    ????????}
    catch(ClassNotFoundException?e){
    ????????????System.out.println(e.toString());
    ????????}
    ????????
    ????}
    ????
    }

    posted @ 2008-08-27 20:41 金家寶 閱讀(291) | 評(píng)論 (0)編輯 收藏

    反向控制和面向切面編程在Spring的應(yīng)用

    引言

      在J2EE的整個(gè)發(fā)展歷程中,現(xiàn)在正是一個(gè)非常時(shí)刻。從很多方面來(lái)說(shuō),J2EE都是一個(gè)偉大的成功:它成功地在從前沒(méi)有標(biāo)準(zhǔn)的地方建立了標(biāo)準(zhǔn);大大提升了企業(yè)級(jí)軟件的開(kāi)放程度,并且得到了整個(gè)行業(yè)和開(kāi)發(fā)者的廣泛認(rèn)可。然而,J2EE在一些方面已經(jīng)開(kāi)始捉襟見(jiàn)肘。J2EE應(yīng)用開(kāi)發(fā)的成本通常很高。J2EE應(yīng)用項(xiàng)目至少和從前的非J2EE項(xiàng)目一樣容易失敗——如果不是更容易失敗的話。這樣的失敗率高得讓人難以接受。在這樣的失敗率之下,軟件開(kāi)發(fā)幾乎變成了碰運(yùn)氣。而在J2EE遭遇失敗的場(chǎng)景中,EJB通常都扮演著重要的角色。因此,J2EE社群不斷地向著更簡(jiǎn)單的解決方案、更少使用EJB的方向發(fā)展[1]。然而,每個(gè)應(yīng)用程序都需要一些基礎(chǔ)設(shè)施,拒絕使用EJB并不意味著拒絕EJB所采用的基礎(chǔ)設(shè)施解決方案。那么,如何利用現(xiàn)有的框架來(lái)提供這些基礎(chǔ)設(shè)施服務(wù)呢,伴隨著這個(gè)問(wèn)題的提出,一個(gè)輕量級(jí)的J2EE解決方案出現(xiàn)了,這就是Spring Framework。

      Spring是為簡(jiǎn)化企業(yè)級(jí)系統(tǒng)開(kāi)發(fā)而誕生的,Spring框架為J2EE應(yīng)用常見(jiàn)的問(wèn)題提供了簡(jiǎn)單、有效的解決方案,使用Spring,你可以用簡(jiǎn)單的POJO(Plain Old Java Object)來(lái)實(shí)現(xiàn)那些以前只有EJB才能實(shí)現(xiàn)的功能。這樣不只是能簡(jiǎn)化服務(wù)器端開(kāi)發(fā),任何Java系統(tǒng)開(kāi)發(fā)都能從Spring的簡(jiǎn)單、可測(cè)試和松耦合特征中受益。可以簡(jiǎn)單的說(shuō),Spring是一個(gè)輕量級(jí)的反向控制(IoC)和面向切面編程(AOP)容器框架[3]。Spring IoC,借助于依賴注入設(shè)計(jì)模式,使得開(kāi)發(fā)者不用理會(huì)對(duì)象自身的生命周期及其關(guān)系,而且能夠改善開(kāi)發(fā)者對(duì)J2EE模式的使用;Spring AOP,借助于Spring實(shí)現(xiàn)的攔截器,開(kāi)發(fā)者能夠?qū)崿F(xiàn)以聲明的方式使用企業(yè)級(jí)服務(wù),比如安全性服務(wù)、事務(wù)服務(wù)等。Spring IoC和 Spring ; AOP組合,一起形成了Spring,這樣一個(gè)有機(jī)整體,使得構(gòu)建輕量級(jí)的J2EE架構(gòu)成為可能,而且事實(shí)證明,非常有效。沒(méi)有Spring IoC的Spring AOP是不完善的,沒(méi)有Spring AOP的Spring IoC是不健壯的。本文是以Spring架構(gòu)的成功的實(shí)際商務(wù)系統(tǒng)項(xiàng)目為背景,闡述了反向控制原理和面向切面的編程技術(shù)在Spring框架中的應(yīng)用,同時(shí)抽取適量代碼示意具體應(yīng)用,并和傳統(tǒng)開(kāi)發(fā)模式進(jìn)行對(duì)比,展示了Spring framework的簡(jiǎn)單,高效,可維護(hù)等優(yōu)點(diǎn)。

      1、Spring IoC 1.1 反向控制原理

      反向控制是Spring框架的核心。但是,反向控制是什么意思?到底控制的什么方面被反向了呢?2004年美國(guó)專家Martin Fowler發(fā)表了一篇論文《Inversion of Control Containers and the Dependency Injection pattern》闡述了這個(gè)問(wèn)題,他總結(jié)說(shuō)是獲得依賴對(duì)象的方式反向了,根據(jù)這個(gè)啟示,他還為反向控制提出了一個(gè)更貼切的名字:Dependency Injection(DI 依賴注入)。

      通常,應(yīng)用代碼需要告知容器或框架,讓它們找到自身所需要的類,然后再由應(yīng)用代碼創(chuàng)建待使用的對(duì)象實(shí)例。因此,應(yīng)用代碼在使用實(shí)例之前,需要?jiǎng)?chuàng)建對(duì)象實(shí)例。然而,IoC模式中,創(chuàng)建對(duì)象實(shí)例的任務(wù)交給IoC容器或框架(實(shí)現(xiàn)了IoC設(shè)計(jì)模式的框架也被稱為IoC容器),使得應(yīng)用代碼只需要直接使用實(shí)例,這就是IoC。相對(duì)IoC 而言,“依賴注入”的確更加準(zhǔn)確的描述了這種設(shè)計(jì)理念。所謂依賴注入,即組件之間的依賴關(guān)系由容器在運(yùn)行期決定,形象的來(lái)說(shuō),即由容器動(dòng)態(tài)的將某種依賴關(guān)系注入到組件之中。

      1.2 IoC在Spring中的實(shí)現(xiàn)

      任何重要的系統(tǒng)都需要至少兩個(gè)相互合作的類來(lái)完成業(yè)務(wù)邏輯。通常,每個(gè)對(duì)象都要自己負(fù)責(zé)得到它的合作(依賴)對(duì)象。你會(huì)發(fā)現(xiàn),這樣會(huì)導(dǎo)致代碼耦合度高而且難于測(cè)試。使用IoC,對(duì)象的依賴都是在對(duì)象創(chuàng)建時(shí)由負(fù)責(zé)協(xié)調(diào)系統(tǒng)中各個(gè)對(duì)象的外部實(shí)體提供的,這樣使軟件組件松散連接成為可能。下面示意了Spring IoC 應(yīng)用,步驟如下:

      (1)定義Action接口,并為其定義一個(gè)execute方法,以完成目標(biāo)邏輯。多年前,GoF在《Design Pattern:Elements of Reusable Object-Oriented Software》一書(shū)中提出“Programming to an Interface,not an implementation”的原則,這里首先將業(yè)務(wù)對(duì)象抽象成接口,正是為了實(shí)施這個(gè)原則。

      (2)類UpperAction實(shí)現(xiàn)Action接口,在此類中,定義一個(gè)String型的域message,并提供相應(yīng)的setter和getter方法,實(shí)現(xiàn)的execute方法如下:

    public String execute (String str) {
     return (getMessage () + str).toUpperCase () ;
    }

      (3)編寫(xiě)Spring配置文件(bean.xml)

    <beans>
    <bean id="TheAction" class="net.chen.spring.qs.UpperAction">
    <property name="message">
    <value>HeLLo</value>
    </property>
    </bean>
    </beans>

      (4)測(cè)試代碼

    public void testQuickStart () {
     ApplicationContext ctx=new
     FileSystemXmlApplicationContext ("bean.xml");
     Action a= (Action) ctx.getBean ("TheAction");
     System.out.println (a. execute ("Rod Johnson"));
    }

      上面的測(cè)試代碼中,我們根據(jù)"bean.xml"創(chuàng)建了一個(gè)ApplicationContext實(shí)例,并從此實(shí)例中獲取我們所需的Action實(shí)現(xiàn),運(yùn)行測(cè)試代碼,我們看到控制臺(tái)輸出:

    ……
    HELLO ROD JOHNSON

      仔細(xì)觀察一下上面的代碼,可以看到:

      (1)我們的組件并不需要實(shí)現(xiàn)框架指定的接口,因此可以輕松的將組件從Spring中脫離,甚至不需要任何修改,這在基于EJB框架實(shí)現(xiàn)的應(yīng)用中是難以想象的。

      (2)組件間的依賴關(guān)系減少,極大改善了代碼的可重用性。Spring的依賴注入機(jī)制,可以在運(yùn)行期為組件配置所需資源,而無(wú)需在編寫(xiě)組件代碼時(shí)就加以指定,從而在相當(dāng)程度上降低了組件之間的耦合。

      Spring給我們帶來(lái)了如此這般的好處,那么,反過(guò)來(lái),讓我們?cè)囅胍幌拢绻皇褂肧pring框架,回到我們傳統(tǒng)的編碼模式,情況會(huì)是怎樣呢?

      首先,我們必須編寫(xiě)一個(gè)配置文件讀取類,以實(shí)現(xiàn)Message屬性的可配置化。

      其次,得有一個(gè)Factory模式的實(shí)現(xiàn),并結(jié)合配置文件的讀寫(xiě)完成Action的動(dòng)態(tài)加載。于是,我們實(shí)現(xiàn)了一個(gè)ActionFactory來(lái)實(shí)現(xiàn)這個(gè)功能:

    public class ActionFactory {
     public static Action getAction (String actionName) {Properties pro = new Properties ();
     try {
      pro.load (new FileInputStream ("config.properties"));
      String actionImplName =(String)pro.get(actionName);
      String actionMessage =(String) pro.get (actionName+"_msg");
      Object obj =Class.forName (actionImplName).newInstance ();
      BeanUtils.setProperty(obj,"message",actionMessage);
      return (Action) obj;
     } catch (FileNotFoundException e) {
      ……
     }
    }

      配置文件則采用properties文件形式如下所示:

    TheAction=net.chen.spring.qs.UpperAction
    TheAction_msg=HeLLo

      測(cè)試代碼也作相應(yīng)修改。現(xiàn)在不論實(shí)現(xiàn)的好壞,總之通過(guò)上面新增的多行代碼,終于實(shí)現(xiàn)了類似的功能。如果現(xiàn)在有了一個(gè)新的需求,這樣這個(gè)ActionFactory每次都新建一個(gè)類的實(shí)例,顯然這對(duì)系統(tǒng)性能不利,考慮到我們的兩個(gè)Action都是線程安全的,修改一下ActionFactory,保持系統(tǒng)中只有一個(gè)Action實(shí)例供其它線程調(diào)用。另外Action對(duì)象創(chuàng)建后,需要做一些初始化工作。修改一下ActionFactory,使其在創(chuàng)建Action實(shí)例之后,隨即就調(diào)用Action.init方法執(zhí)行初始化。Action的處理這樣就差不多了。下面我們來(lái)看看另外一個(gè)Factory

      ……

      往往這些系統(tǒng)開(kāi)發(fā)中最常見(jiàn)的需求,會(huì)導(dǎo)致我們的代碼迅速膨脹,而Spring IoC的出現(xiàn),則大大緩解了這樣的窘境。通過(guò)以上實(shí)例,可以看出,Spring IoC為我們提供了如下幾方面的優(yōu)勢(shì):

      (1)應(yīng)用組件不需要在運(yùn)行時(shí)尋找其協(xié)作者,因此更易于開(kāi)發(fā)和編寫(xiě)應(yīng)用;

      (2)由于借助于IoC容器管理組件的依賴關(guān)系,使得應(yīng)用的單元測(cè)試和集成測(cè)試更利于展開(kāi);

      (3)通常,在借助于IoC容器關(guān)系業(yè)務(wù)對(duì)象的前提下,很少需要使用具體IoC容器提供的API,這使得集成現(xiàn)有的遺留應(yīng)用成為可能。

      因此,通過(guò)使用IoC能夠降低組件之間的耦合度,最終,能夠提高類的重用性,利于測(cè)試,而且更利于整個(gè)產(chǎn)品或系統(tǒng)集成和配置。
    2、Spring AOP

      2.1 面向切面編程基礎(chǔ)

      通常,系統(tǒng)由很多組件組成,每個(gè)組件負(fù)責(zé)一部分功能,然而,這些組件也經(jīng)常帶有一些除了核心功能之外的附帶功能 。系統(tǒng)服務(wù)如日志、事務(wù)管理和安全經(jīng)常融入到一些其他功能模塊中。這些系統(tǒng)服務(wù)通常叫做交叉業(yè)務(wù),這是因?yàn)樗鼈兛偸欠植荚谙到y(tǒng)的很多組件中。通過(guò)將這些業(yè)務(wù)分布在多個(gè)組件中,給我們的代碼引入了雙重復(fù)雜性。

      (1) 實(shí)現(xiàn)系統(tǒng)級(jí)業(yè)務(wù)的代碼在多個(gè)組件中復(fù)制。這意味著如果你要改變這些業(yè)務(wù)邏輯,你就必須到各個(gè)模塊去修改。就算把這些業(yè)務(wù)抽象成一個(gè)獨(dú)立模塊,其它模塊只是調(diào)用它的一個(gè)方法,但是這個(gè)方法調(diào)用也還是分布在很多地方。

      (2) 組件會(huì)因?yàn)槟切┡c自己核心業(yè)務(wù)無(wú)關(guān)的代碼變得雜亂。一個(gè)向地址錄中添加條目的方法應(yīng)該只關(guān)心如何添加地址,而不是關(guān)心它是不是安全或支持事務(wù)的。

      此時(shí),我們?cè)撛趺崔k呢?這正是AOP用得著的地方。AOP幫助我們將這些服務(wù)模塊化,并把它們聲明式地應(yīng)用在需要它們的地方,使得這些組件更加專注于自身業(yè)務(wù),完全不知道其它涉及到的系統(tǒng)服務(wù)。

      這里的概念切面,就是我們要實(shí)現(xiàn)的交叉功能,是應(yīng)用系統(tǒng)模塊化的一個(gè)方面或領(lǐng)域。切面的最常見(jiàn)例子就是日志記錄。日志記錄在系統(tǒng)中到處需要用到,利用繼承來(lái)重用日志模塊是不合適的,這樣,就可以創(chuàng)建一個(gè)日志記錄切面,并且使用AOP在系統(tǒng)中應(yīng)用。下圖展示了切面應(yīng)用方式


    圖表 1 應(yīng)用切面

      其中,通知Advice是切面的實(shí)際實(shí)現(xiàn)。連接點(diǎn)Joinpoint是應(yīng)用程序執(zhí)行過(guò)程中插入切面的地點(diǎn),這個(gè)地點(diǎn)可以是方法調(diào)用,異常拋出,甚至可以是要修改的字段,切面代碼在這些地方插入到你的應(yīng)用流程中,添加新的行為。切入點(diǎn)Pointcut定義了Advice應(yīng)該應(yīng)用在那些連接點(diǎn),通常通過(guò)指定類名和方法名,或者匹配類名和方法名式樣的正則表達(dá)式來(lái)指定切入點(diǎn)。

      2.2 AOP在Spring中的實(shí)現(xiàn)

      基于AOP,業(yè)界存在各種各樣的AOP實(shí)現(xiàn),比如,JBoss AOP、Spring AOP、AspectJ、Aspect Werkz等。各自實(shí)現(xiàn)的功能也不一樣。AOP實(shí)現(xiàn)的強(qiáng)弱在很大程度上取決于連接點(diǎn)模型。目前,Spring只支持方法級(jí)的連接點(diǎn)。這和一些其他AOP框架不一樣,如AspectJ和JBoss,它們還提供了屬性接入點(diǎn),這樣可以防止你創(chuàng)建特別細(xì)致的通知,如對(duì)更新對(duì)象屬性值進(jìn)行攔截。然而,由于Spring關(guān)注于提供一個(gè)實(shí)現(xiàn)J2EE服務(wù)的框架,所以方法攔截可以滿足大部分要求,而且Spring的觀點(diǎn)是屬性攔截破壞了封裝,讓Advice觸發(fā)在屬性值改變而不是方法調(diào)用上無(wú)疑是破壞了這個(gè)概念。

      Spring的AOP框架的關(guān)鍵點(diǎn)如下:

      (1)Spring實(shí)現(xiàn)了AOP聯(lián)盟接口。在Spring AOP中,存在如下幾種通知(Advice)類型

      Before通知:在目標(biāo)方法被調(diào)用前調(diào)用,涉及接口org.springframework.aop.MethodBeforeAdvice;

      After通知:在目標(biāo)方法被調(diào)用后調(diào)用,涉及接口為org.springframework.aop.AfterReturningAdvice;

      Throws通知:目標(biāo)方法拋出異常時(shí)調(diào)用,涉及接口org.springframework.aop.MethodBeforeAdvice;

      Around通知:攔截對(duì)目標(biāo)對(duì)象方法調(diào)用,涉及接口為org.aopalliance.intercept.MethodInterceptor。

      (2)用java編寫(xiě)Spring通知,并在Spring的配置文件中,定義在什么地方應(yīng)用通知的切入點(diǎn)。

      (3)Spring的運(yùn)行時(shí)通知對(duì)象。代理Bean只有在第一次被應(yīng)用系統(tǒng)需要的時(shí)候才被創(chuàng)建。如果你使用的是ApplicationContext,代理對(duì)象在BeanFactory載入所有Bean的時(shí)候被創(chuàng)建。Spring有兩種代理創(chuàng)建方式。如果目標(biāo)對(duì)象實(shí)現(xiàn)了一個(gè)或多個(gè)接口暴露的方法,Spring將使用JDK的java.lang.reflect.Proxy類創(chuàng)建代理。這個(gè)類讓Spring動(dòng)態(tài)產(chǎn)生一個(gè)新的類,它實(shí)現(xiàn)所需的接口,織入了通知,并且代理對(duì)目標(biāo)對(duì)象的所有請(qǐng)求。如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)任何接口,Spring使用CGLIB庫(kù)生成目標(biāo)對(duì)象的子類。在創(chuàng)建這個(gè)子類的時(shí)候,Spring將通知織入,并且將對(duì)目標(biāo)對(duì)象的調(diào)用委托給這個(gè)子類。此時(shí),需要將Spring發(fā)行包lib/cglib目錄下的JAR文件發(fā)布到應(yīng)用系統(tǒng)中。

      2.3 Spring AOP的優(yōu)勢(shì)

      借助于Spring AOP,Spring IoC能夠很方便的使用到非常健壯、靈活的企業(yè)級(jí)服務(wù),是因?yàn)镾pring AOP能夠提供如下幾方面的優(yōu)勢(shì):

      (1)允許開(kāi)發(fā)者使用聲明式企業(yè)服務(wù),比如事務(wù)服務(wù)、安全性服務(wù);EJB開(kāi)發(fā)者都知道,EJB組件能夠使用J2EE容器提供的聲明式服務(wù),但是這些服務(wù)要借助于EJB容器,而Spring AOP卻不需要EJB容器,借助于Spring的事務(wù)抽象框架就可以這些服務(wù)。

      (2)開(kāi)發(fā)者可以開(kāi)發(fā)滿足業(yè)務(wù)需求的自定義切面;

      (3)開(kāi)發(fā)Spring AOP Advice很方便。因?yàn)檫@些AOP Advice僅是POJO類,借助于Spring提供的ProxyFactoryBean,能夠快速的搭建Spring AOP Advice。

      3、結(jié)語(yǔ)

      本文詳細(xì)闡述了Spring背后的IoC原理和AOP技術(shù),以實(shí)際成功項(xiàng)目為背景,抽取簡(jiǎn)短片斷,展示了Spring架構(gòu)J2EE應(yīng)用系統(tǒng)的原理。Spring IoC借助于依賴注入機(jī)制,減輕了組件之間的依賴關(guān)系,同時(shí)也大大提高了組件的可移植性,組件得到了更多的重用機(jī)會(huì)。借助于Spring AOP,使得開(kāi)發(fā)者能聲明式、基于元數(shù)據(jù)訪問(wèn)企業(yè)級(jí)服務(wù),AOP合理補(bǔ)充了OOP技術(shù),Spring AOP合理地補(bǔ)充了Spring IoC容器。Spring IoC與Spring AOP組合,使得Spring成為成功的J2EE架構(gòu)框架,并能與標(biāo)準(zhǔn)的EJB等標(biāo)準(zhǔn)對(duì)抗,EJB不再是必需品。Spring已經(jīng)沖入了J2EE的核心,將引領(lǐng)整個(gè)J2EE開(kāi)發(fā)、架構(gòu)的方向。

    posted @ 2008-08-25 18:08 金家寶 閱讀(231) | 評(píng)論 (0)編輯 收藏

    GoF設(shè)計(jì)模式

    著名的EJB領(lǐng)域頂尖的專家Richard Monson-Haefel在其個(gè)人網(wǎng)站:www.EJBNow.com中極力推薦的GoF的《設(shè)計(jì)模式》,原文如下:

    Design Patterns
    Most developers claim to experience an epiphany reading this book. If you've never read the Design Patterns book then you have suffered a very serious gap in your programming education that should be remedied immediately.

    翻譯: 很多程序員在讀完這本書(shū),宣布自己相當(dāng)于經(jīng)歷了一次"主顯節(jié)"(紀(jì)念那穌降生和受洗的雙重節(jié)日),如果你從來(lái)沒(méi)有讀過(guò)這本書(shū),你會(huì)在你的程序教育生涯里存在一個(gè)嚴(yán)重裂溝,所以你應(yīng)該立即挽救彌補(bǔ)!

    可以這么說(shuō):GoF設(shè)計(jì)模式是程序員真正掌握面向?qū)ο蠛诵乃枷氲谋匦拚n。雖然你可能已經(jīng)通過(guò)了SUN的很多令人炫目的技術(shù)認(rèn)證,但是如果你沒(méi)有學(xué)習(xí)掌握GoF設(shè)計(jì)模式,只能說(shuō)明你還是一個(gè)技工。

    在瀏覽《Thingking in Java》(第一版)時(shí),你是不是覺(jué)得好象這還是一本Java基礎(chǔ)語(yǔ)言書(shū)籍?但又不純粹是,因?yàn)檫@本書(shū)的作者將面向?qū)ο蟮乃枷肭擅畹娜诤显贘ava的具體技術(shù)上,潛移默化的讓你感覺(jué)到了一種新的語(yǔ)言和新的思想方式的誕生。

    但是讀完這本書(shū),你對(duì)書(shū)中這些蘊(yùn)含的思想也許需要一種更明晰更系統(tǒng)更透徹的了解和掌握,那么你就需要研讀GoF的《設(shè)計(jì)模式》了。

    《Thingking in Java》(第一版中文)是這樣描述設(shè)計(jì)模式的:他在由Gamma, Helm和Johnson Vlissides簡(jiǎn)稱Gang of Four(四人幫),縮寫(xiě)GoF編著的《Design Patterns》一書(shū)中被定義成一個(gè)“里程碑”。事實(shí)上,那本書(shū)現(xiàn)在已成為幾乎所有OOP(面向?qū)ο蟪绦蛟O(shè)計(jì))程序員都必備的參考書(shū)。(在國(guó)外是如此)。

    GoF的《設(shè)計(jì)模式》是所有面向?qū)ο笳Z(yǔ)言(C++ Java C#)的基礎(chǔ),只不過(guò)不同的語(yǔ)言將之實(shí)現(xiàn)得更方便地使用。

    GOF的設(shè)計(jì)模式是一座"橋"
    就Java語(yǔ)言體系來(lái)說(shuō),GOF的設(shè)計(jì)模式是Java基礎(chǔ)知識(shí)和J2EE框架知識(shí)之間一座隱性的"橋"。

    會(huì)Java的人越來(lái)越多,但是一直徘徊在語(yǔ)言層次的程序員不在少數(shù),真正掌握J(rèn)ava中接口或抽象類的應(yīng)用不是很多,大家經(jīng)常以那些技術(shù)只適合大型項(xiàng)目為由,避開(kāi)或忽略它們,實(shí)際中,Java的接口或抽象類是真正體現(xiàn)Java思想的核心所在,這些你都將在GoF的設(shè)計(jì)模式里領(lǐng)略到它們變幻無(wú)窮的魔力。

    GoF的設(shè)計(jì)模式表面上好象也是一種具體的"技術(shù)",而且新的設(shè)計(jì)模式不斷在出現(xiàn),設(shè)計(jì)模式自有其自己的發(fā)展軌道,而這些好象和J2EE .Net等技術(shù)也無(wú)關(guān)!

    實(shí)際上,GoF的設(shè)計(jì)模式并不是一種具體"技術(shù)",它講述的是思想,它不僅僅展示了接口或抽象類在實(shí)際案例中的靈活應(yīng)用和智慧,讓你能夠真正掌握接口或抽象類的應(yīng)用,從而在原來(lái)的Java語(yǔ)言基礎(chǔ)上躍進(jìn)一步,更重要的是,GoF的設(shè)計(jì)模式反復(fù)向你強(qiáng)調(diào)一個(gè)宗旨:要讓你的程序盡可能的可重用。

    這其實(shí)在向一個(gè)極限挑戰(zhàn):軟件需求變幻無(wú)窮,計(jì)劃沒(méi)有變化快,但是我們還是要尋找出不變的東西,并將它和變化的東西分離開(kāi)來(lái),這需要非常的智慧和經(jīng)驗(yàn)。

    而GoF的設(shè)計(jì)模式是在這方面開(kāi)始探索的一塊里程碑。

    J2EE等屬于一種框架軟件,什么是框架軟件?它不同于我們以前接觸的Java API等,那些屬于Toolkist(工具箱),它不再被動(dòng)的被使用,被調(diào)用,而是深刻的介入到一個(gè)領(lǐng)域中去,J2EE等框架軟件設(shè)計(jì)的目的是將一個(gè)領(lǐng)域中不變的東西先定義好,比如整體結(jié)構(gòu)和一些主要職責(zé)(如數(shù)據(jù)庫(kù)操作 事務(wù)跟蹤 安全等),剩余的就是變化的東西,針對(duì)這個(gè)領(lǐng)域中具體應(yīng)用產(chǎn)生的具體不同的變化需求,而這些變化東西就是J2EE程序員所要做的。

    由此可見(jiàn),設(shè)計(jì)模式和J2EE在思想和動(dòng)機(jī)上是一脈相承,只不過(guò)

    1.設(shè)計(jì)模式更抽象,J2EE是具體的產(chǎn)品代碼,我們可以接觸到,而設(shè)計(jì)模式在對(duì)每個(gè)應(yīng)用時(shí)才會(huì)產(chǎn)生具體代碼。

    2.設(shè)計(jì)模式是比J2EE等框架軟件更小的體系結(jié)構(gòu),J2EE中許多具體程序都是應(yīng)用設(shè)計(jì)模式來(lái)完成的,當(dāng)你深入到J2EE的內(nèi)部代碼研究時(shí),這點(diǎn)尤其明顯,因此,如果你不具備設(shè)計(jì)模式的基礎(chǔ)知識(shí)(GoF的設(shè)計(jì)模式),你很難快速的理解J2EE。不能理解J2EE,如何能靈活應(yīng)用?

    3.J2EE只是適合企業(yè)計(jì)算應(yīng)用的框架軟件,但是GoF的設(shè)計(jì)模式幾乎可以用于任何應(yīng)用!因此GoF的設(shè)計(jì)模式應(yīng)該是J2EE的重要理論基礎(chǔ)之一。

    所以說(shuō),GoF的設(shè)計(jì)模式是Java基礎(chǔ)知識(shí)和J2EE框架知識(shí)之間一座隱性的"橋"。為什么說(shuō)隱性的?

    GOF的設(shè)計(jì)模式是一座隱性的"橋"
    因?yàn)楹芏嗳藳](méi)有注意到這點(diǎn),學(xué)完Java基礎(chǔ)語(yǔ)言就直接去學(xué)J2EE,有的甚至鴨子趕架,直接使用起Weblogic等具體J2EE軟件,一段時(shí)間下來(lái),發(fā)現(xiàn)不過(guò)如此,挺簡(jiǎn)單好用,但是你真正理解J2EE了嗎?你在具體案例中的應(yīng)用是否也是在延伸J2EE的思想?

    如果你不能很好的延伸J2EE的思想,那你豈非是大炮轟蚊子,認(rèn)識(shí)到J2EE不是適合所有場(chǎng)合的人至少是明智的,但我們更需要將J2EE用對(duì)地方,那么只有理解J2EE此類框架軟件的精髓,那么你才能真正靈活應(yīng)用Java解決你的問(wèn)題,甚至構(gòu)架出你自己企業(yè)的框架來(lái)。(我們不能總是使用別人設(shè)定好的框架,為什么不能有我們自己的框架?)

    因此,首先你必須掌握GoF的設(shè)計(jì)模式。雖然它是隱性,但不是可以越過(guò)的。

    ?

    關(guān)于本站“設(shè)計(jì)模式”

    Java提供了豐富的API,同時(shí)又有強(qiáng)大的數(shù)據(jù)庫(kù)系統(tǒng)作底層支持,那么我們的編程似乎變成了類似積木的簡(jiǎn)單"拼湊"和調(diào)用,甚至有人提倡"藍(lán)領(lǐng)程序員",這些都是對(duì)現(xiàn)代編程技術(shù)的不了解所至.

    在真正可復(fù)用的面向?qū)ο缶幊讨?GoF的《設(shè)計(jì)模式》為我們提供了一套可復(fù)用的面向?qū)ο蠹夹g(shù),再配合Refactoring(重構(gòu)方法),所以很少存在簡(jiǎn)單重復(fù)的工作,加上Java代碼的精煉性和面向?qū)ο蠹儩嵭?設(shè)計(jì)模式是java的靈魂),編程工作將變成一個(gè)讓你時(shí)刻體驗(yàn)創(chuàng)造快感的激動(dòng)人心的過(guò)程.

    為能和大家能共同探討"設(shè)計(jì)模式",我將自己在學(xué)習(xí)中的心得寫(xiě)下來(lái),只是想幫助更多人更容易理解GoF的《設(shè)計(jì)模式》。由于原著都是以C++為例, 以Java為例的設(shè)計(jì)模式基本又都以圖形應(yīng)用為例,而我們更關(guān)心Java在中間件等服務(wù)器方面的應(yīng)用,因此,本站所有實(shí)例都是非圖形應(yīng)用,并且順帶剖析Jive論壇系統(tǒng).同時(shí)為降低理解難度,盡量避免使用UML圖.

    如果你有一定的面向?qū)ο缶幊探?jīng)驗(yàn),你會(huì)發(fā)現(xiàn)其中某些設(shè)計(jì)模式你已經(jīng)無(wú)意識(shí)的使用過(guò)了;如果你是一個(gè)新手,那么從開(kāi)始就培養(yǎng)自己良好的編程習(xí)慣(讓你的的程序使用通用的模式,便于他人理解;讓你自己減少重復(fù)性的編程工作),這無(wú)疑是成為一個(gè)優(yōu)秀程序員的必備條件.

    整個(gè)設(shè)計(jì)模式貫穿一個(gè)原理:面對(duì)接口編程,而不是面對(duì)實(shí)現(xiàn).目標(biāo)原則是:降低耦合,增強(qiáng)靈活性.

    posted @ 2008-07-07 11:05 金家寶 閱讀(279) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲尹人香蕉网在线视颅| 亚洲免费福利在线视频| 亚洲AV无码专区在线电影成人 | 亚洲中文字幕无码一去台湾| 久久国产亚洲电影天堂| 亚洲成av人片天堂网| 亚洲综合精品香蕉久久网| 亚洲精品线路一在线观看| 丁香亚洲综合五月天婷婷| 免费一级毛片不卡在线播放 | 免费中文字幕视频| 亚洲理论片在线中文字幕| 亚洲高清在线视频| 97人伦色伦成人免费视频| 在线免费观看h片| 在线视频网址免费播放| 本免费AV无码专区一区| a级毛片免费在线观看| 真人做A免费观看| 日韩免费电影网站| 午夜在线免费视频| 亚洲精品无播放器在线播放| 亚洲美国产亚洲AV| 亚洲另类自拍丝袜第1页| 亚洲国产精品日韩在线| 在线观看亚洲AV每日更新无码 | 不卡一卡二卡三亚洲| 国产日产亚洲系列| 亚洲欧洲国产精品香蕉网| 亚洲av综合色区| 亚洲综合在线成人一区| 美女视频黄频a免费观看| 亚洲AV无码无限在线观看不卡| 亚洲国产女人aaa毛片在线| 亚洲欧洲免费无码| 免费看无码特级毛片| 国产免费A∨在线播放| h视频在线免费观看| 无码精品一区二区三区免费视频| 国产裸体美女永久免费无遮挡| 国产自国产自愉自愉免费24区|