志當(dāng)存高遠(yuǎn),功到自然成!

          少年強(qiáng)則中國(guó)強(qiáng),少年進(jìn)步則中國(guó)進(jìn)步!

          BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
            53 Posts :: 2 Stories :: 2 Comments :: 0 Trackbacks

          2008年11月13日 #

          mysql 5.1支持觸發(fā)器以及自定義函數(shù)接口(UDF)的特性,如果配合libmemcache以及Memcached Functions for MySQL,就能夠?qū)崿F(xiàn)memcache的自動(dòng)更新。簡(jiǎn)單記錄一下安裝測(cè)試步驟。

            mysql 5.1支持觸發(fā)器以及自定義函數(shù)接口(UDF)的特性,如果配合libmemcache以及Memcached Functions for MySQL,就能夠?qū)崿F(xiàn)memcache的自動(dòng)更新。簡(jiǎn)單記錄一下安裝測(cè)試步驟。

            安裝步驟

            安裝memcached,這個(gè)步驟很簡(jiǎn)單,隨處可見(jiàn)。安裝mysql server 5.1RC,安裝辦法也很大眾,不廢話 了。

            編譯libmemcached,解壓后安裝即可./configure; make; make install

            編譯Memcached Functions for MySQL,在http://download.tangent.org/找一個(gè)最新的版本下載就 是,./configure --with-mysql=/usr/local/mysql/bin/mysql_config -- libdir=/usr/local/mysql/lib/mysql/

            make

            make install

            接下來(lái)有兩個(gè)辦法讓Memcached Functions for MySQL在mysql中生效。

            在mysql的shell中執(zhí)行memcached_functions_mysql源碼目錄下的sql/install_functions.sql,這會(huì) 把memcache function作為UDF加入mysql。

            運(yùn)行memcached_functions_mysql源碼目錄下的utils/install.pl,這是一個(gè)perl腳本,作用同上一 條。

            測(cè)試memcache function。

            以下測(cè)試腳本摘自memcached_functions_mysql的源碼目錄,有興趣可以試試。


          PLAIN TEXTCODE: drop table if exists urls;
          create table urls (
          id int(3) not null,
          url varchar(64) not null default '',
          primary key (id)
          );
          select memc_servers_set('localhost:11211');
          select memc_set('urls:sequence', 0);
          DELIMITER |
          DROP TRIGGER IF EXISTS url_mem_insert;
          CREATE TRIGGER url_mem_insert
          BEFORE INSERT ON urls
          FOR EACH ROW BEGIN
          SET NEW.id= memc_increment('urls:sequence');
          SET @mm= memc_set(concat('urls:',NEW.id), NEW.url);
          END |
          DELIMITER ;
          insert into urls (url) values ('http://google.com');
          insert into urls (url) values ('http://www.ooso.net/index.php');
          insert into urls (url) values ('http://www.ooso.net/');
          insert into urls (url) values ('http://slashdot.org');
          insert into urls (url) values ('http://mysql.com');
          select * from urls;
          select memc_get('urls:1');
          select memc_get('urls:2');
          select memc_get('urls:3');
          select memc_get('urls:4');
          select memc_get('urls:5');
          posted @ 2010-08-12 15:22 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(477) | 評(píng)論 (0)編輯 收藏

          假設(shè)我們有3臺(tái)memcached 服務(wù)器,server1 和server2 有3GB 的內(nèi)存空間,server3 有2GB 的內(nèi)存空間.
          下面程序說(shuō)明怎么來(lái)創(chuàng)建客戶端.
          import com.danga.MemCached.*;

          public class MyClass {

          // 創(chuàng)建一個(gè) memcached 客戶端對(duì)象

          protected static MemCachedClient mcc = new MemCachedClient();

          // 創(chuàng)建  memcached連接池

          static

          {  // 指定memcached服務(wù)地址 String[] servers =
          { "server1.mydomain.com:1121","server2.mydomain.com:1121",
          "server3.mydomain.com:1121" };
          // 指定memcached服務(wù)器負(fù)載量
          Integer[]  weights    ={ 3, 3, 2 };
          // 從連接池獲取一個(gè)連接實(shí)例

          SockIOPool pool = SockIOPool.getInstance();

          // 設(shè)置服務(wù)器和服務(wù)器負(fù)載量

          pool.setServers( servers );

          pool.setWeights( weights );

          // 設(shè)置一些基本的參數(shù)

          //設(shè)置初始連接數(shù)5   最小連接數(shù) 5   最大連接數(shù) 250

          //設(shè)置一個(gè)連接最大空閑時(shí)間6小時(shí)

          pool.setInitConn( 5 );

          pool.setMinConn( 5 );

          pool.setMaxConn( 250 );

          pool.setMaxIdle( 1000 * 60 * 60 * 6 );

          // 設(shè)置主線程睡眠時(shí)間

          // 每隔30秒醒來(lái)  然后

          // 開(kāi)始維護(hù) 連接數(shù)大小

          pool.setMaintSleep( 30 );

          // 設(shè)置tcp 相關(guān)的樹(shù)形

          // 關(guān)閉nagle算法

          // 設(shè)置 讀取 超時(shí)3秒鐘  set the read timeout to 3 secs

          //  不設(shè)置連接超時(shí)

          pool.setNagle( false );

          pool.setSocketTO( 3000 );

          pool.setSocketConnectTO( 0 );

          // 開(kāi)始初始化 連接池

          pool.initialize();

          // 設(shè)置壓縮模式

          //如果超過(guò)64k壓縮數(shù)據(jù)

          mcc.setCompressEnable( true );

          mcc.setCompressThreshold( 64 * 1024 );

          }

          public static void examples() {

          mcc.set( "foo", "This is a test String" );

          String bar = mcc.get( "foo" );

          }

          }
          MemCachedClient 類 常用的方法說(shuō)明

          創(chuàng)建 client對(duì)象 設(shè)置參數(shù):

          MemCachedClient mc = new MemCachedClient();
          //壓縮模式
          mc.setCompressEnable(true);
          // 如果 cache數(shù)據(jù) 大于4 KB  就啟用壓縮
          mc.setCompressThreshold(4096);
          // 基本類型tostring方法
          // 通常不需要設(shè)置
          mc.setPrimitiveAsString(true);
          存儲(chǔ)一個(gè)對(duì)象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          Object value = SomeClass.getObject();

          mc.set(key, value);
          用客戶端hashcode 存儲(chǔ)一個(gè)對(duì)象:


          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          Object value = SomeClass.getObject();

          Integer hash = new Integer(45);

          mc.set(key, value, hash);

          set方法:在cache中存儲(chǔ)一個(gè)指定對(duì)象

             add 和replace 方法功能差不多

            add -- 如果不存在 這個(gè)key的對(duì)象,將會(huì)存儲(chǔ)一個(gè)對(duì)象到cache中
            replace --只有當(dāng)存在指定key對(duì)象的時(shí)候 會(huì)覆蓋已有對(duì)象
          刪除一個(gè)對(duì)象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          mc.delete(key);
          結(jié)合hashcode 刪除一個(gè)對(duì)象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          Integer hash = new Integer(45);

          mc.delete(key, hashCode);
          怎么cache計(jì)數(shù),增 減計(jì)數(shù):

          MemCachedClient mc = new MemCachedClient();

          String key   = "counterKey";

          mc.storeCounter(key, new Integer(100));

          System.out.println("counter after adding      1: " mc.incr(key));

          System.out.println("counter after adding      5: " mc.incr(key, 5));

          System.out.println("counter after subtracting 4: " mc.decr(key, 4));

          System.out.println("counter after subtracting 1: " mc.decr(key));
          利用客戶端的hashcode存儲(chǔ)計(jì)數(shù) 增減 計(jì)數(shù):

          MemCachedClient mc = new MemCachedClient();

          String key   = "counterKey";

          Integer hash = new Integer(45);

          mc.storeCounter(key, new Integer(100), hash);

          System.out.println("counter after adding      1: " mc.incr(key, 1, hash));

          System.out.println("counter after adding      5: " mc.incr(key, 5, hash));

          System.out.println("counter after subtracting 4: " mc.decr(key, 4, hash));

          System.out.println("counter after subtracting 1: " mc.decr(key, 1, hash));
          獲取一個(gè)對(duì)象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "key";

          Object value = mc.get(key);
          用客戶端hashcode獲取一個(gè)對(duì)象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "key";

          Integer hash = new Integer(45);

          Object value = mc.get(key, hash);
          MemCachedClient mc = new MemCachedClient();

          String key   = "key";

          Integer hash = new Integer(45);

          Object value = mc.get(key, hash);
          從cache 中獲取多個(gè)對(duì)象

          MemCachedClient mc = new MemCachedClient();

          String[] keys      ={ "key", "key1", "key2" };Mapvalues = mc.getMulti(keys);
          用客戶端hashcode 從cache中獲取多個(gè)對(duì)象
          MemCachedClient mc = new MemCachedClient();
          String[] keys      = { "key", "key1", "key2" };

          Integer[] hashes   =
          { new Integer(45), new Integer(32), new Integer(44) };
          Mapvalues = mc.getMulti(keys, hashes);
          清空所有的對(duì)象
          MemCachedClient mc = new MemCachedClient();

          mc.flushAll();
          得到服務(wù)器memcached的狀態(tài)信息
          MemCachedClient mc = new MemCachedClient();

          Map stats = mc.stats();
          注意點(diǎn)
          1:Failover/Failback
          當(dāng)一個(gè)memcached服務(wù)器失效的時(shí)候客戶端默認(rèn)會(huì)failover另一個(gè)服務(wù)去.

          如果失效的服務(wù)器 恢復(fù)運(yùn)行,客戶端會(huì)返回到原來(lái)連接的服務(wù)器.
          如果你不想用這個(gè)功能 設(shè)置下面的參數(shù)
          pool.setFailover( false );
          pool.setFailback( false );

          2:序列化

          Boolean
          Byte
          String
          Character
          StringBuffer
          StringBuilder
          Short
          Long
          Double
          Float
          Date
          java默認(rèn)的類型沒(méi)有實(shí)現(xiàn)序列化 可以設(shè)置
          mcc.setPrimitiveAsString( true )替代.
          Meetup.com實(shí)踐過(guò)程中得出的一個(gè)經(jīng)驗(yàn) ,項(xiàng)目中model 對(duì)象implement Externalizable 實(shí)現(xiàn)序列化,
          可以節(jié)省cache 對(duì)象的大小。從而節(jié)省網(wǎng)絡(luò)帶寬和內(nèi)存空間。
          posted @ 2010-08-11 23:21 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(10778) | 評(píng)論 (1)編輯 收藏

          一:硬架構(gòu)

          1 :機(jī)房的選擇:

          在 選擇機(jī)房的時(shí)候,根據(jù)網(wǎng)站用戶的地域分布,可以選擇網(wǎng)通或電信機(jī)房,但更多時(shí)候,可能雙線機(jī)房才是合適的。越大的城市,機(jī)房?jī)r(jià)格越貴,從成本的角度看可以 在一些中小城市托管服務(wù)器,比如說(shuō)廣州的公司可以考慮把服務(wù)器托管在東莞,佛山等地,不是特別遠(yuǎn),但是價(jià)格會(huì)便宜很多。

          2 :帶寬的大小:

          通常老板花錢(qián)請(qǐng)我們架構(gòu)網(wǎng)站的時(shí)候,會(huì)給我們提出一些目標(biāo),諸如網(wǎng)站每天要能承受100 萬(wàn)PV 的訪問(wèn)量等等。這時(shí)我們要預(yù)算一下大概需要多大的帶寬,計(jì)算帶寬大小主要涉及兩個(gè)指標(biāo)(峰值流量和頁(yè)面大小),我們不妨在計(jì)算前先做出必要的假設(shè):

          第一:假設(shè)峰值流量是平均流量的5 倍。
          第二:假設(shè)每次訪問(wèn)平均的頁(yè)面大小是100K 字節(jié)左右。

          如果100 萬(wàn)PV 的訪問(wèn)量在一天內(nèi)平均分布的話,折合到每秒大約12 次訪問(wèn),如果按平均每次訪問(wèn)頁(yè)面的大小是100K 字節(jié)左右計(jì)算的話,這12 次訪 問(wèn)總計(jì)大約就是1200K 字節(jié),字節(jié)的單位是Byte ,而帶寬的單位是bit ,它們之間的關(guān)系是1Byte = 8bit ,所以1200K Byte 大致就相當(dāng)于9600K bit ,也就是9Mbps 的樣子,實(shí)際情況中,我們的網(wǎng)站必須能在峰值流量時(shí)保持正常訪問(wèn),所以按照假設(shè)的峰值流量算,真實(shí)帶寬的需求應(yīng)該在45Mbps  左右。

          當(dāng)然,這個(gè)結(jié)論是建立在前面提到的兩點(diǎn)假設(shè)的基礎(chǔ)上,如果你的實(shí)際情況和這兩點(diǎn)假設(shè)有出入,那么結(jié)果也會(huì)有差別。

          3 :服務(wù)器的劃分:

          先看我們都需要哪些服務(wù)器:圖片服務(wù)器,頁(yè)面服務(wù)器,數(shù)據(jù)庫(kù)服務(wù)器,應(yīng)用服務(wù)器,日志服務(wù)器等等。

          對(duì)于訪問(wèn)量大點(diǎn)的網(wǎng)站而言,分離單獨(dú)的圖片服務(wù)器和頁(yè)面服務(wù)器相當(dāng)必要,我們可以用lighttpd 來(lái)跑圖片服務(wù)器,用apache 來(lái)跑頁(yè)面服務(wù) 器,當(dāng)然也可以選擇別的,甚至,我們可以擴(kuò)展成很多臺(tái)圖片服務(wù)器和很多臺(tái)頁(yè)面服務(wù)器,并設(shè)置相關(guān)域名,如img.domain.com 和 www.domain.com ,頁(yè)面里的圖片路徑都使用絕對(duì)路徑,如<img src="http://img.domain.com/abc.gif" /> ,然后設(shè)置DNS 輪循,達(dá)到最初級(jí)的負(fù)載均衡。當(dāng)然,服務(wù)器多了就不可避免的涉及一個(gè)同步的問(wèn)題,這個(gè)可以使用rsync 軟件來(lái)搞定。

          數(shù)據(jù)庫(kù)服務(wù)器是重中之重,因?yàn)榫W(wǎng)站的瓶頸問(wèn)題十有八九是出在數(shù)據(jù)庫(kù)身上。現(xiàn)在一般的中小網(wǎng)站多使用MySQL 數(shù)據(jù)庫(kù),不過(guò)它的集群功能似乎還沒(méi)有達(dá) 到stable 的階段,所以這里不做評(píng)價(jià)。一般而言,使用MySQL 數(shù)據(jù)庫(kù)的時(shí)候,我們應(yīng)該搞一個(gè)主從(一主多從)結(jié)構(gòu),主數(shù)據(jù)庫(kù)服務(wù)器使用innodb  表結(jié)構(gòu),從數(shù)據(jù)服務(wù)器使用myisam 表結(jié)構(gòu),充分發(fā)揮它們各自的優(yōu)勢(shì),而且這樣的主從結(jié)構(gòu)分離了讀寫(xiě)操作,降低了讀操作的壓力,甚至我們還可以設(shè)定一個(gè)專門(mén)的從服務(wù)器做備份服務(wù)器,方便備份。不然如果你只有一臺(tái)主服務(wù)器,在大數(shù)據(jù)量的情況下,mysqldump 基本就沒(méi)戲了,直接拷貝數(shù)據(jù)文件的話,還得先停止數(shù)據(jù)庫(kù)服務(wù)再拷貝,否則備份文件會(huì)出錯(cuò)。但對(duì)于很多網(wǎng)站而言,即使數(shù)據(jù)庫(kù)服務(wù)僅停止了一秒也是不可接受的。如果你有了一臺(tái)從數(shù)據(jù)庫(kù)服務(wù)器,在備份數(shù) 據(jù)的時(shí)候,可以先停止服務(wù)(slave stop )再備份,再啟動(dòng)服務(wù)(slave start )后從服務(wù)器會(huì)自動(dòng)從主服務(wù)器同步數(shù)據(jù),一切都沒(méi)有影響。但是主從結(jié)構(gòu)也是有致命缺點(diǎn)的,那就是主從結(jié)構(gòu)只是降低了讀操作的壓力,卻不能降低寫(xiě)操作的壓力。為了適應(yīng)更大的規(guī)模,可能只剩下最后這招了:橫向/ 縱向分割數(shù)據(jù)庫(kù)。所謂橫向分割數(shù)據(jù)庫(kù),就是把不同的表保存到不同的數(shù)據(jù)庫(kù)服務(wù)器上,比如說(shuō)用戶表保存在A 數(shù)據(jù)庫(kù)服務(wù)器上,文章表保存在B 數(shù)據(jù)庫(kù)服務(wù)器上,當(dāng)然這樣的分割是有代價(jià)的,最基本的就是你沒(méi)法進(jìn)行LEFT JOIN 之類的操作了。所謂縱向分割數(shù)據(jù)庫(kù),一般是指按照用戶標(biāo)識(shí)(user_id )等來(lái)劃分?jǐn)?shù)據(jù)存儲(chǔ)的服務(wù)器,比如說(shuō):我們有5 臺(tái)數(shù)據(jù)庫(kù)服務(wù)器,那么 “user_id % 5 + 1” 等于1 的就保存到1 號(hào)服務(wù)器,等于2 的就保存到2 好服務(wù)器,以此類推,縱向分隔的原則有很多種,可以視情況選擇。不過(guò)和橫向分割數(shù)據(jù)庫(kù)一樣,縱向分割 數(shù)據(jù)庫(kù)也是有代價(jià)的,最基本的就是我們?cè)谶M(jìn)行如COUNT, SUM 等匯總操作的時(shí)候會(huì)麻煩很多。綜上所述,數(shù)據(jù)庫(kù)服務(wù)器的解決方案一般視情況往往是一個(gè)混合的方案,以其發(fā)揮各種方案的優(yōu)勢(shì),有時(shí)候還需要借助 memcached 之類的第三方軟件,以便適應(yīng)更大訪問(wèn)量的要求。

          如果有專門(mén)的應(yīng)用服務(wù)器來(lái)跑PHP 腳本是最合適不過(guò)的了,那樣我們的頁(yè)面服務(wù)器只保存靜態(tài)頁(yè)面就可以了,可以給應(yīng)用服務(wù)器設(shè)置一些諸如 app.domain.com 之類的域名來(lái)和頁(yè)面服務(wù)器加以區(qū)別。對(duì)于應(yīng)用服務(wù)器,我還是更傾向于使用prefork 模式的apache ,配上必要的 xcache 之類的PHP 緩存軟件,加載模塊要越少越好,除了mod_rewrite 等必要的模塊,不必要的東西統(tǒng)統(tǒng)舍棄,盡量減少httpd 進(jìn)程的內(nèi)存消耗,而那些圖片服務(wù)器,頁(yè)面服務(wù)器等靜態(tài)內(nèi)容就可以使用lighttpd 或者tux 來(lái)搞,充分發(fā)揮各種服務(wù)器的特點(diǎn)。

          如果條件允許,獨(dú)立的日志服務(wù)器也是必要的,一般小網(wǎng)站的做法都是把頁(yè)面服務(wù)器和日志服務(wù)器合二為一了,在凌晨訪問(wèn)量不大的時(shí)候cron 運(yùn)行前一天 的日志計(jì)算,不過(guò)如果你使用awstats 之類的日志分析軟件,對(duì)于百萬(wàn)級(jí)訪問(wèn)量而言,即使按天歸檔,也會(huì)消耗很多時(shí)間和服務(wù)器資源去計(jì)算,所以分離單獨(dú)的日志服務(wù)器還是有好處的,這樣不會(huì)影響正式服務(wù)器的工作狀態(tài)。

          二:軟架構(gòu)

          1 :框架的選擇:

          現(xiàn)在的PHP 框架有很多選擇,比如:CakePHP ,Symfony ,Zend Framework 等等,至于應(yīng)該使用哪一個(gè)并沒(méi)有唯一的答案,要根據(jù)Team 里團(tuán)隊(duì)成員對(duì)各個(gè)框架的了解程度而定。很多時(shí)候,即使沒(méi)有使用框架,一樣能寫(xiě)出好的程序來(lái),比如Flickr 據(jù)說(shuō)就是用Pear+Smarty 這樣的類庫(kù)寫(xiě)出來(lái)的,所以是否用框架,用什么框架,一般不是最重要,重要的是我們的編程思想里要有框架的意識(shí)。

          現(xiàn)在的.NET 框架有很多選擇,比如:cnForums ,.text ,cs, Castle, 等等

          2 :邏輯的分層:

          網(wǎng)站規(guī)模到了一定的程度之后,代碼里各種邏輯糾纏在一起,會(huì)給維護(hù)和擴(kuò)展帶來(lái)巨大的障礙,這時(shí)我們的解決方式其實(shí)很簡(jiǎn)單,那就是重構(gòu),將邏輯進(jìn)行分層。通常,自上而下可以分為表現(xiàn)層,應(yīng)用層,領(lǐng)域?qū)樱志脤印?/font>

          所 謂表現(xiàn)層,并不僅僅就指模板,它的范圍要更廣一些,所有和表現(xiàn)相關(guān)的邏輯都應(yīng)該被納入表現(xiàn)層的范疇。比如說(shuō)某處的字體要顯示為紅色,某處的開(kāi)頭要空兩格, 這些都屬于表現(xiàn)層。很多時(shí)候,我們?nèi)菀追傅腻e(cuò)誤就是把本屬于表現(xiàn)層的邏輯放到了其他層面去完成,這里說(shuō)一個(gè)很常見(jiàn)的例子:我們?cè)诹斜眄?yè)顯示文章標(biāo)題的時(shí) 候,都會(huì)設(shè)定一個(gè)最大字?jǐn)?shù),一旦標(biāo)題長(zhǎng)度超過(guò)了這個(gè)限制,就截?cái)啵⒃诤竺骘@示“..” ,這就是最典型的表現(xiàn)層邏輯,但是實(shí)際情況,有很多程序員都是在非表現(xiàn)層代碼里完成數(shù)據(jù)的獲取和截?cái)啵缓筚x值給表現(xiàn)層模板,這樣的代碼最直接的缺點(diǎn)就是同樣一段數(shù)據(jù),在這個(gè)頁(yè)面我可能想顯示前10 個(gè)字,再另一個(gè) 頁(yè)面我可能想顯示前15 個(gè)字,而一旦我們?cè)诔绦蚶锕袒诉@個(gè)字?jǐn)?shù),也就喪失了可移植性。正確的做法是應(yīng)該做一個(gè)視圖助手之類的程序來(lái)專門(mén)處理此類邏輯,比如說(shuō):Smarty 里的truncate 就屬于這樣的視圖助手(不過(guò)它那個(gè)實(shí)現(xiàn)不適合中文)。

          所謂應(yīng)用層,它的主要作用是定義用戶可以做什么,并把操作結(jié)果反饋給表現(xiàn)層。至于如何做,通常不是它的職責(zé)范圍(而是領(lǐng)域?qū)拥穆氊?zé)范圍),它會(huì)通過(guò)委派把如何做的工作交給領(lǐng)域?qū)尤ヌ幚怼T谑褂肕VC 架構(gòu)的網(wǎng)站中,我們可以看到類似下面這樣的URL :domain.com/articles/view/123 ,其內(nèi)部編碼實(shí)現(xiàn),一般就是一個(gè)Articles 控制器類,里面有一個(gè)view 方法,這就是一 個(gè)典型的應(yīng)用層操作,因?yàn)樗x了用戶可以做一個(gè)查看的動(dòng)作。在MVC 架構(gòu)中,有一個(gè)準(zhǔn)則是這么說(shuō)的:Rich Model Is Good 。言外之意,就是Controller 要保持“ 瘦” 一些比較好,進(jìn)而說(shuō)明應(yīng)用層要盡量簡(jiǎn)單,不要包括涉及領(lǐng)域內(nèi)容的邏輯。

          所謂領(lǐng)域?qū)樱钪苯拥慕忉尵褪前I(lǐng)域邏輯的層。它是一個(gè)軟件的靈魂所在。先來(lái)看看什么叫領(lǐng)域邏輯,簡(jiǎn)單的說(shuō),具有明確的領(lǐng)域概念的邏輯就是領(lǐng)域邏輯,比如我們?cè)贏TM 機(jī)上取錢(qián),過(guò)程大致是這樣的:插入銀聯(lián)卡,輸入密碼,輸入取款金額,確定,拿錢(qián),然后ATM 吐出一個(gè)交易憑條。在這個(gè)過(guò)程中,銀聯(lián)卡 在ATM 機(jī)器里完成錢(qián)從帳戶上劃撥的過(guò)程就是一個(gè)領(lǐng)域邏輯,因?yàn)槿″X(qián)在銀行中是一個(gè)明確的領(lǐng)域概念,而ATM 機(jī)吐出一個(gè)交易憑條則不是領(lǐng)域邏輯,而僅是一 個(gè)應(yīng)用邏輯,因?yàn)橥鲁鼋灰讘{條并不是銀行中一個(gè)明確的領(lǐng)域概念,只是一種技術(shù)手段,對(duì)應(yīng)的,我們?nèi)″X(qián)后不吐交易憑條,而發(fā)送一條提醒短信也是可能的,但并 不是一定如此,如果在實(shí)際情況中,我們要求取款后必須吐出交易憑條,也就是說(shuō)吐出交易憑條已經(jīng)和取款緊密結(jié)合,那么你也可以把吐出交易憑條看作是領(lǐng)域邏輯 的一部分,一切都以問(wèn)題的具體情況而定。在Eric 那本經(jīng)典的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中,把領(lǐng)域?qū)臃譃榱宋宸N基本元素:實(shí)體,值對(duì)象,服務(wù),工廠,倉(cāng)儲(chǔ)。具體可以參 閱書(shū)中的介紹。領(lǐng)域?qū)幼畛7傅腻e(cuò)誤就是把本應(yīng)屬于領(lǐng)域?qū)拥倪壿嬓孤兜搅似渌麑哟危热缯f(shuō)在一個(gè)CMS 系統(tǒng),對(duì)熱門(mén)文章的定義是這樣的:每天被瀏覽的次數(shù)多 于1000 次,被評(píng)論的次數(shù)多于100 次,這樣的文章就是熱門(mén)文章。對(duì)于一個(gè)CMS 來(lái)說(shuō),熱門(mén)文章這個(gè)詞無(wú)疑是一個(gè)重要的領(lǐng)域概念,那么我們?nèi)绾螌?shí)現(xiàn)這個(gè)邏輯的設(shè)計(jì)的?你可能會(huì)給出類似下面的代碼:“SELECT ... FROM ... WHERE  瀏覽 > 1000 AND  評(píng)論 > 100” ,沒(méi)錯(cuò),這是最簡(jiǎn)單的實(shí)現(xiàn)方式,但是這里需要注意的是“ 每天被瀏覽的次數(shù)多于1000 次,被評(píng)論的次數(shù)多于100 次” 這個(gè)重要的領(lǐng)域邏輯被隱藏到了SQL 語(yǔ)句中,SQL 語(yǔ)句顯然不屬于領(lǐng)域?qū)拥姆懂牐簿褪钦f(shuō),我們的領(lǐng)域邏輯泄露了。

          所謂持久層,就是指把我們的領(lǐng)域模型保存到數(shù)據(jù)庫(kù)中。因?yàn)槲覀兊某绦虼a是面向?qū)ο箫L(fēng)格的,而數(shù)據(jù)庫(kù)一般是關(guān)系型的數(shù)據(jù)庫(kù),所以我們需要把領(lǐng)域模型 碾平,才能保存到數(shù)據(jù)庫(kù)中,但是在 PHP 里,直到目前還沒(méi)有非常好的 ORM 出現(xiàn),所以這方面的解決方案不是特別多,參考 Martin 的企業(yè)應(yīng)用架構(gòu)模式一   書(shū),大致可以使用的方法有行數(shù)據(jù)入口( Row Data Gateway )或者表數(shù)據(jù)入口( Table Data Gateway),或者把領(lǐng)域?qū)雍统志脤雍隙橐蛔兂苫顒?dòng)記錄(Active Record)的方式。

          posted @ 2010-08-11 14:32 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(433) | 評(píng)論 (0)編輯 收藏

          TOMCAT崩潰事件

          http://www.aygfsteel.com/tedeyang/archive/2008/06/04/205740.html

          今天一大早產(chǎn)品一部項(xiàng)目經(jīng)理就來(lái)找我,他們的一臺(tái)服務(wù)器昨天晚上tomcat服務(wù)崩潰,還不能重啟服務(wù),最后將服務(wù)器重啟才OK。
          我將事件過(guò)程和分析過(guò)程記錄如下:

          服務(wù)器:win 2000 sp4,apache 2 + tomcat 5.0 采用mod_jk級(jí)聯(lián)。內(nèi)存2G,硬盤(pán)剩余空間充足,CPU基本空閑。
          主要應(yīng)用:J2EE 1.4,JDBC(連接另一臺(tái)mysql服務(wù)器)
          崩潰時(shí)間: 2008-6-3 18:37:50

          一.各種日志綜合如下:

             1.37分45秒,操作系統(tǒng)事件中諾頓殺毒軟件報(bào)內(nèi)存過(guò)低警報(bào)
             2.37分45秒,web應(yīng)用拋出JDBC連接異常:

          2008-06-03 18:37:45 cn.*.db.DBManager.getConnection(DBManager.java:157) ERROR swim.db.DBManager   com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception:
          ** BEGIN NESTED EXCEPTION **
          java.net.SocketException
          MESSAGE: java.net.SocketException: No buffer 
          space available (maximum connections reached?): JVM_Bind


             3.37分50秒,tomcat拋出session無(wú)法save異常:

          2008-06-03 18:37:50 ERROR- IOException while saving persisted sessions: java.io.FileNotFoundException: "izzs"SESSIONS.ser (系統(tǒng)資源不足,無(wú)法完成請(qǐng)求的服務(wù)。)
          java.io.FileNotFoundException: "izzs"SESSIONS.ser (系統(tǒng)資源不足,無(wú)法完成請(qǐng)求的服務(wù)。)
              at java.io.FileOutputStream.open(Native Method)
              at java.io.FileOutputStream.
          <init>(FileOutputStream.java:179)
              at java.io.FileOutputStream.
          <init>(FileOutputStream.java:70)
              at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:
          511)
              at org.apache.catalina.session.StandardManager.unload(StandardManager.java:
          485)
              at org.apache.catalina.session.StandardManager.stop(StandardManager.java:
          687)
              at org.apache.catalina.core.StandardContext.stop(StandardContext.java:
          4496)
              at org.apache.catalina.core.StandardContext.reload(StandardContext.java:
          3037)
              at org.apache.catalina.core.StandardContext.backgroundProcess(StandardContext.java:
          4658)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
          1619)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
          1628)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
          1628)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:
          1608)
              at java.lang.Thread.run(Thread.java:
          534)


           

          二.簡(jiǎn)單分析

          崩潰原因:內(nèi)存不足導(dǎo)致資源不足,引起Tomcat的session崩潰。
            這臺(tái)服務(wù)器上運(yùn)行著很多應(yīng)用,是什么原因引起內(nèi)存不足還無(wú)法確定。
          初步判斷罪魁禍?zhǔn)卓赡苁莂pache,該進(jìn)程平常占用500MB內(nèi)存,經(jīng)常會(huì)飚到1G以上。

          Apache2的配置文件中:KeepAlive=On,MaxKeepAliveRequests=100,KeepAliveTimeout=15,分析aceess.log文件可以發(fā)現(xiàn)每個(gè)頁(yè)面觸發(fā)的request數(shù)量在10個(gè)以下,點(diǎn)擊率較低,可能使連接過(guò)多。
          我建議將keepAlive設(shè)為off,增加CPU負(fù)載,降低內(nèi)存消耗。

          三.效果

           有待觀察......

          參考資料:
          http://www.withend.com/post/78.html

          四.結(jié)局 
          時(shí)隔一天,晚上九點(diǎn)再次崩潰,黑暗事件重演。
          這一次,我才得知原來(lái)該apache還配置有其他域名,于是調(diào)出該域名下的access.log。項(xiàng)目經(jīng)理去了機(jī)房,在轟轟地風(fēng)扇聲中打電話給我,讓我分析分析。
          仔細(xì)看訪問(wèn)日志,發(fā)現(xiàn)原來(lái)有N多Connect 443連接,443是什么?是SSL端口!HTTPS!,Connect命令則顯然是代理功能!
          而且這些connect的IP來(lái)自全球各地,加拿大、美國(guó)、澳洲、新西蘭、北京、上海、英國(guó)、哪都有。
          看來(lái)這臺(tái)服務(wù)器是被人當(dāng)代理服務(wù)器用了。
          怪不得半夜會(huì)死機(jī),人家西半球那時(shí)正大白天撒歡兒呢。

          問(wèn)題就出在apache的配置上,由于應(yīng)用眾多,并且這臺(tái)服務(wù)器還是其他幾臺(tái)web服務(wù)器的對(duì)外出口,因此apache中配置了反向代理,不過(guò)不小心把正向代理(mod_proxy模塊的ProxyRequests指令)也打開(kāi)了。
          看看apache2.0的官方文檔中mod_proxy部分,里面明明白白寫(xiě)著:

          警告
          在您沒(méi)有對(duì)服務(wù)器采取安全措施之前,請(qǐng)不要用ProxyRequests啟用您的代理。一個(gè)開(kāi)放的代理服務(wù)器不僅對(duì)您的網(wǎng)絡(luò)有威脅,對(duì)整個(gè)因特網(wǎng)來(lái)說(shuō)也同樣如此。
          真的是很有威脅!大量代理請(qǐng)求急劇消耗內(nèi)存,最終造成死機(jī)!

          解決辦法就是把正向代理關(guān)掉:ProxyRequests Off
          posted @ 2010-08-11 14:25 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(2036) | 評(píng)論 (0)編輯 收藏

          分布式緩存系統(tǒng)Memcached簡(jiǎn)介與實(shí)踐

          http://blog.csdn.net/hitman9099/archive/2008/09/04/2878417.aspx

           

          緣起: 在數(shù)據(jù)驅(qū)動(dòng)的web開(kāi)發(fā)中,經(jīng)常要重復(fù)從數(shù)據(jù)庫(kù)中取出相同的數(shù)據(jù),這種重復(fù)極大的增加了數(shù)據(jù)庫(kù)負(fù)載。緩存是解決這個(gè)問(wèn)題的好辦法。但是ASP.NET中的雖然已經(jīng)可以實(shí)現(xiàn)對(duì)頁(yè)面局部進(jìn)行緩存,但還是不夠靈活。此時(shí)Memcached或許是你想要的。

          Memcached是什么?
          Memcached是由Danga Interactive開(kāi)發(fā)的,高性能的,分布式的內(nèi)存對(duì)象緩存系統(tǒng),用于在動(dòng)態(tài)應(yīng)用中減少數(shù)據(jù)庫(kù)負(fù)載,提升訪問(wèn)速度。

          Memcached能緩存什么?
          通過(guò)在內(nèi)存里維護(hù)一個(gè)統(tǒng)一的巨大的hash表,Memcached能夠用來(lái)存儲(chǔ)各種格式的數(shù)據(jù),包括圖像、視頻、文件以及數(shù)據(jù)庫(kù)檢索的結(jié)果等。

          Memcached快么?

          非 常快。Memcached使用了libevent(如果可以的話,在linux下使用epoll)來(lái)均衡任何數(shù)量的打開(kāi)鏈接,使用非阻塞的網(wǎng)絡(luò)I/O,對(duì) 內(nèi)部對(duì)象實(shí)現(xiàn)引用計(jì)數(shù)(因此,針對(duì)多樣的客戶端,對(duì)象可以處在多樣的狀態(tài)), 使用自己的頁(yè)塊分配器和哈希表, 因此虛擬內(nèi)存不會(huì)產(chǎn)生碎片并且虛擬內(nèi)存分配的時(shí)間復(fù)雜度可以保證為O(1).。

          Danga Interactive為提升Danga Interactive的速度研發(fā)了Memcached。目前,LiveJournal.com每天已經(jīng)在向一百萬(wàn)用戶提供多達(dá)兩千萬(wàn)次的頁(yè)面訪問(wèn)。而這 些,是由一個(gè)由web服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器組成的集群完成的。Memcached幾乎完全放棄了任何數(shù)據(jù)都從數(shù)據(jù)庫(kù)讀取的方式,同時(shí),它還縮短了用戶查看 頁(yè)面的速度、更好的資源分配方式,以及Memcache失效時(shí)對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)速度。

          Memcached的特點(diǎn)
          Memcached的緩存是一種分布式的,可以讓不同主機(jī)上的多個(gè)用戶同時(shí)訪問(wèn), 因此解決了共享內(nèi)存只能單機(jī)應(yīng)用的局限,更不會(huì)出現(xiàn)使用數(shù)據(jù)庫(kù)做類似事情的時(shí)候,磁盤(pán)開(kāi)銷和阻塞的發(fā)生。

          Memcached的使用 
           
          Memcached服務(wù)器端的安裝 (此處將其作為系統(tǒng)服務(wù)安裝)
          下載文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
              1 解壓縮文件到c:\memcached
             2 命令行輸入 'c:\memcached\memcached.exe -d install' 
              3 命令行輸入 'c:\memcached\memcached.exe -d start' ,該命令啟動(dòng) Memcached ,默認(rèn)監(jiān)聽(tīng)端口為 11211
          通過(guò) memcached.exe -h 可以查看其幫助

           

          一個(gè)簡(jiǎn)單的測(cè)試?yán)?/p>

          1. package com.mapbar.util.cache;

          2. import java.util.Date;
          3. import java.util.ResourceBundle;

          4. import com.danga.MemCached.MemCachedClient;
          5. import com.danga.MemCached.SockIOPool;
          6. /**
          7.  * 使用配置文件方式的memcache組件
          8.  *
          9.  */
          10. public class Cache {

          11.  protected static ResourceBundle rb=ResourceBundle.getBundle("memcached");;
          12.  public static MemCachedClient mcc = new MemCachedClient(); 
          13.  static {
          14.   init();
          15.  }     
          16.  public static void init(){
          17.   synchronized (mcc) {  
          18.    System.out.println("init call");
          19.    String[] servers =rb.getString("cache.servers").split(",");       
          20.          
          21.          String[] strWeights =rb.getString("cache.weights").split(",");  
          22.          Integer[] weights = new Integer[strWeights.length];
          23.          for(int i=0;i<strWeights.length;i++){
          24.           weights[i]=Integer.parseInt(strWeights[i]);
          25.          }
          26.         
          27.          //創(chuàng)建一個(gè)實(shí)例對(duì)象SockIOPool     
          28.          SockIOPool pool = SockIOPool.getInstance();       
          29.         
          30.          // set the servers and the weights    
          31.          //設(shè)置Memcached Server    
          32.          pool.setServers( servers );       
          33.          pool.setWeights( weights );       
          34.          pool.setInitConn(Integer.parseInt(rb.getString("cache.initConn")));       
          35.          pool.setMinConn(Integer.parseInt(rb.getString("cache.minConn")));       
          36.          pool.setMaxConn(Integer.parseInt(rb.getString("cache.maxConn")));       
          37.          pool.setMaxIdle(Long.parseLong(rb.getString("cache.maxIdle")));       
          38.         
          39.          // set the sleep for the maint thread       
          40.          // it will wake up every x seconds and       
          41.          // maintain the pool size       
          42.          pool.setMaintSleep( 30 );       
          43.         
          44. //         Tcp的規(guī)則就是在發(fā)送一個(gè)包之前,本地機(jī)器會(huì)等待遠(yuǎn)程主機(jī)    
          45. //         對(duì)上一次發(fā)送的包的確認(rèn)信息到來(lái);這個(gè)方法就可以關(guān)閉套接字的緩存,    
          46. //         以至這個(gè)包準(zhǔn)備好了就發(fā);    
          47.          pool.setNagle( false );       
          48.          //連接建立后對(duì)超時(shí)的控制    
          49.          pool.setSocketTO( 3000 );    
          50.          //連接建立時(shí)對(duì)超時(shí)的控制    
          51.          pool.setSocketConnectTO( 0 );       
          52.         
          53.          // initialize the connection pool       
          54.          //初始化一些值并與MemcachedServer段建立連接    
          55.          pool.initialize();    

          56.          // lets set some compression on for the client       
          57.          // compress anything larger than 64k       
          58.          mcc.setCompressEnable( true );       
          59.          mcc.setCompressThreshold( 64 * 1024 );  
          60.   }
          61.  }
          62.  protected static void bulidCache(){  
          63.   
          64.         //set(key,value,Date) ,Date是一個(gè)過(guò)期時(shí)間,如果想讓這個(gè)過(guò)期時(shí)間生效的話,這里傳遞的new Date(long date) 中參數(shù)date,需要是個(gè)大于或等于1000的值。    
          65.         //因?yàn)閖ava client的實(shí)現(xiàn)源碼里是這樣實(shí)現(xiàn)的 expiry.getTime() / 1000 ,也就是說(shuō),如果 小于1000的值,除以1000以后都是0,即永不過(guò)期    
          66.         mcc.set( "test""This is a test String" ,new Date(100000));   //十秒后過(guò)期    
          67.               
          68.     }       
          69.       
          70.  protected static void output() {       
          71.         //從cache里取值    
          72.         String value = (String) mcc.get( "test" );       
          73.         System.out.println(value);        
          74.     }       
          75.            
          76.  public static void main(String[] args){       
          77.         bulidCache();      
          78.         output();           
          79.     }        

          80. }


          其中在classespath下有個(gè)memcached.properties文件

          內(nèi)容如下:

          ##muti servers spilt by ,

          #這里是你的memcached啟動(dòng)的地址
          cache.servers=192.168.0.116:11211  
          cache.weights=1
          #memcached be used
          cache.cluster=true

          #set some basic pool settings       
          #5 initial, 5 min, and 250 max conns       
          #and set the max idle time for a conn       
          #to 6 hours  6*60*60*1000
          cache.initConn=5
          cache.minConn=5
          cache.maxConn=250
          cache.maxIdle=21600000

           

           

           

           

          在Windows下安裝Memcached

          http://www.oschina.net/docs/article/4

          很多phper不知道如何在Windows下搭建Memcache的開(kāi)發(fā)調(diào)試環(huán)境,最近個(gè)人也在研究Memcache,記錄下自己安裝搭建的過(guò)程。
          其實(shí)我開(kāi)始研究Memcache的時(shí)候并不知道居然還有memcached for Win32這個(gè)鳥(niǎo)東西,害得我在CnetOS下折騰1天才搞定,今天突然發(fā)現(xiàn)Windows下的Memcache進(jìn)行開(kāi)發(fā)調(diào)試完全沒(méi)有問(wèn)題,所以寫(xiě)篇 Memcache的文檔分享給大家。

          Windows下的Memcache安裝
          1. 下載memcache的 windows穩(wěn)定版,解壓放某個(gè)盤(pán)下面,比如在c:\memcached
          2. 在終端(也即cmd命令界面)下輸入 ‘c:\memcached\memcached.exe -d install’ 安裝
          3. 再輸入: ‘c:\memcached\memcached.exe -d start’ 啟動(dòng)。NOTE: 以后memcached將作為windows的一個(gè)服務(wù)每次開(kāi)機(jī)時(shí)自動(dòng)啟動(dòng)。這樣服務(wù)器端已經(jīng)安裝完畢了。
          4.下載php_memcache.dll, 請(qǐng)自己查找對(duì)應(yīng)的php版本的文件
          5. 在C:\winnt\php.ini 加入一行 ‘extension=php_memcache.dll’
          6.重新啟動(dòng)Apache,然后查看一下phpinfo,如果有memcache,那么就說(shuō)明安裝成功!

          memcached的基本設(shè)置

          -p 監(jiān)聽(tīng)的端口
          -l 連接的IP地址, 默認(rèn)是本機(jī)
          -d start 啟動(dòng)memcached服務(wù)
          -d restart 重起memcached服務(wù)
          -d stop|shutdown 關(guān)閉正在運(yùn)行的memcached服務(wù)
          -d install 安裝memcached服務(wù)
          -d uninstall 卸載memcached服務(wù)
          -u 以的身份運(yùn)行 (僅在以root運(yùn)行的時(shí)候有效)
          -m 最大內(nèi)存使用,單位MB。默認(rèn)64MB
          -M 內(nèi)存耗盡時(shí)返回錯(cuò)誤,而不是刪除項(xiàng)
          -c 最大同時(shí)連接數(shù),默認(rèn)是1024
          -f 塊大小增長(zhǎng)因子,默認(rèn)是1.25
          -n 最小分配空間,key+value+flags默認(rèn)是48
          -h 顯示幫助

          Memcache環(huán)境測(cè)試
          運(yùn)行下面的php文件,如果有輸出This is a test!,就表示環(huán)境搭建成功。開(kāi)始領(lǐng)略Memcache的魅力把!
          < ?php
          $mem = new Memcache;
          $mem->connect(”127.0.0.1″, 11211);
          $mem->set(’key’, ‘This is a test!’, 0, 60);
          $val = $mem->get(’key’);
          echo $val;
          ?>

          posted @ 2010-08-11 14:22 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(467) | 評(píng)論 (0)編輯 收藏

          日志原文:http://j2ee.blog.sohu.com/70343632.html   
          memcache for win 軟件主頁(yè):http://jehiah.cz/projects/memcached-win32/  
          http://labs.northscale.com/memcached-packages/
          meecache for liunx 軟件主頁(yè):http://memcached.org/  
                                               
          最近一直在做一個(gè)項(xiàng)目的前期設(shè)計(jì)工作,考慮到后期系統(tǒng)的擴(kuò)展和性能問(wèn)題也找了很多解決方法,有一個(gè)就是用到了數(shù)據(jù)庫(kù)的緩存工具memcached(當(dāng)然該工具并不僅僅局限于數(shù)據(jù)庫(kù)的緩存)。先簡(jiǎn)單的介紹下什么是memcached。

              Memcached是高性能的,分布式的內(nèi)存對(duì)象緩存系統(tǒng),用于在動(dòng)態(tài)應(yīng)用中減少數(shù)據(jù)庫(kù)負(fù) 載,提升訪問(wèn)速度。Memcached由Danga Interactive開(kāi)發(fā),用于提升LiveJournal.com訪問(wèn)速度的。LJ每秒動(dòng)態(tài)頁(yè)面訪問(wèn)量幾千次,用戶700萬(wàn)。Memcached將數(shù) 據(jù)庫(kù)負(fù)載大幅度降低,更好的分配資源,更快速訪問(wèn)。

              上網(wǎng)baidu了很多東西,幾乎都差不多,而且基于java的說(shuō)的很少,所有只有在研究了各個(gè)其他語(yǔ)言類的應(yīng)用后再來(lái)嘗試在java上進(jìn)行簡(jiǎn)單的操作應(yīng) 用。先從memcached上進(jìn)行說(shuō)明,memcached的最新版是采用c語(yǔ)言進(jìn)行開(kāi)發(fā)和設(shè)計(jì)的,據(jù)說(shuō)舊版的是采用perl語(yǔ)言開(kāi)發(fā)的,而且它是一個(gè)應(yīng) 用軟件來(lái)的,是作為緩存服務(wù)器的服務(wù)器端運(yùn)行在服務(wù)器上的,需要使用特定的語(yǔ)言編寫(xiě)客戶端與其進(jìn)行通信來(lái)進(jìn)行數(shù)據(jù)的緩存和獲取。通常我們是把 memcached安裝運(yùn)行在web服務(wù)器上,然后通過(guò)對(duì)需要的數(shù)據(jù)進(jìn)行緩存,據(jù)我目前所知,所有數(shù)據(jù)的緩存設(shè)置和存取操作,以及數(shù)據(jù)的更新后替換操作全 部需要程序來(lái)進(jìn)行,而不是自動(dòng)進(jìn)行的(自動(dòng)不知道能不能成功,呵呵)。下面從一個(gè)實(shí)際的例子來(lái)應(yīng)用memcached。

              首先到http://danga.com/memcached/下 載memcached的windows版本和java客戶端jar包,目前最新版本是memcached-1.2.1-win32.zip和 java_memcached-release_1.6.zip,分別解壓后即可!首先是安裝運(yùn)行memcached服務(wù)器,我們將memcached- 1.2.1-win32.zip解壓后,進(jìn)入其目錄,然后運(yùn)行如下命令:

          c:>memcached.exe -d install
          c:>memcached.exe -l 127.0.0.1 -m 32 -d start

              第一行是安裝memcached成為服務(wù),這樣才能正常運(yùn)行,否則運(yùn)行失敗!第一行是啟動(dòng)memcached的,作為測(cè)試我們就簡(jiǎn)單的只分配32M內(nèi)存 了,然后監(jiān)聽(tīng)本機(jī)端口和以守護(hù)進(jìn)行運(yùn)行。執(zhí)行完畢后,我們就可以在任務(wù)管理器中見(jiàn)到memcached.exe這個(gè)進(jìn)程了。好了,我們的服務(wù)器已經(jīng)正常運(yùn) 行了, 下面我們就來(lái)寫(xiě)java的客戶端連接程序。

              我們將java_memcached-release_1.6.zip解壓后的目錄中的java_memcached-release_1.6.jar文件復(fù)制到j(luò)ava項(xiàng)目的lib目錄下,然后我們來(lái)編寫(xiě)代碼,比如我提供的一個(gè)應(yīng)用類如下:

          package utils.cache;

          import java.util.Date;

          import com.danga.MemCached.MemCachedClient;
          import com.danga.MemCached.SockIOPool;


          /**
          * 使用memcached的緩存實(shí)用類.
          *
          *
          @author 鐵木箱子
          *
          */
          public class MemCached
          {
             
          // 創(chuàng)建全局的唯一實(shí)例
              protected static MemCachedClient mcc = new MemCachedClient();
             
             
          protected static MemCached memCached = new MemCached();
             
             
          // 設(shè)置與緩存服務(wù)器的連接池
              static {
                 
          // 服務(wù)器列表和其權(quán)重
                  String[] servers = {"127.0.0.1:11211"};
                  Integer[] weights
          = {3};

                 
          // 獲取socke連接池的實(shí)例對(duì)象
                  SockIOPool pool = SockIOPool.getInstance();

                 
          // 設(shè)置服務(wù)器信息
                  pool.setServers( servers );
                  pool.setWeights( weights );

                 
          // 設(shè)置初始連接數(shù)、最小和最大連接數(shù)以及最大處理時(shí)間
                  pool.setInitConn( 5 );
                  pool.setMinConn(
          5 );
                  pool.setMaxConn(
          250 );
                  pool.setMaxIdle(
          1000 * 60 * 60 * 6 );

                 
          // 設(shè)置主線程的睡眠時(shí)間
                  pool.setMaintSleep( 30 );

                 
          // 設(shè)置TCP的參數(shù),連接超時(shí)等
                  pool.setNagle( false );
                  pool.setSocketTO(
          3000 );
                  pool.setSocketConnectTO(
          0 );

                 
          // 初始化連接池
                  pool.initialize();

                 
          // 壓縮設(shè)置,超過(guò)指定大小(單位為K)的數(shù)據(jù)都會(huì)被壓縮
                  mcc.setCompressEnable( true );
                  mcc.setCompressThreshold(
          64 * 1024 );
              }
             
             
          /**
               * 保護(hù)型構(gòu)造方法,不允許實(shí)例化!
               *
              
          */
             
          protected MemCached()
              {
                 
              }
             
             
          /**
               * 獲取唯一實(shí)例.
               *
          @return
              
          */
             
          public static MemCached getInstance()
              {
                 
          return memCached;
              }
             
             
          /**
               * 添加一個(gè)指定的值到緩存中.
               *
          @param key
               *
          @param value
               *
          @return
              
          */
             
          public boolean add(String key, Object value)
              {
                 
          return mcc.add(key, value);
              }
             
             
          public boolean add(String key, Object value, Date expiry)
              {
                 
          return mcc.add(key, value, expiry);
              }
             
             
          public boolean replace(String key, Object value)
              {
                 
          return mcc.replace(key, value);
              }
             
             
          public boolean replace(String key, Object value, Date expiry)
              {
                 
          return mcc.replace(key, value, expiry);
              }
             
             
          /**
               * 根據(jù)指定的關(guān)鍵字獲取對(duì)象.
               *
          @param key
               *
          @return
              
          */
             
          public Object get(String key)
              {
                 
          return mcc.get(key);
              }
             
             
          public static void main(String[] args)
              {
                  MemCached cache
          = MemCached.getInstance();
                  cache.add(
          "hello", 234);
                  System.out.print(
          "get value : " + cache.get("hello"));
              }
          }

              那么我們就可以通過(guò)簡(jiǎn)單的像main方法中操作的一樣存入一個(gè)變量,然后再取出進(jìn)行查看,我們可以看到先調(diào)用了add,然后再進(jìn)行g(shù)et,我們運(yùn)行一次 后,234這個(gè)值已經(jīng)被我們存入了memcached的緩存中的了,我們將main方法中紅色的那一行注釋掉后,我們?cè)龠\(yùn)行還是可以看到get到的 value也是234,即緩存中我們已經(jīng)存在了數(shù)據(jù)了。

              對(duì)基本的數(shù)據(jù)我們可以操作,對(duì)于普通的POJO而言,如果要進(jìn)行存儲(chǔ)的話,那么比如讓其實(shí)現(xiàn)java.io.Serializable接口,因?yàn)? memcached是一個(gè)分布式的緩存服務(wù)器,多臺(tái)服務(wù)器間進(jìn)行數(shù)據(jù)共享需要將對(duì)象序列化的,所以必須實(shí)現(xiàn)該接口,否則會(huì)報(bào)錯(cuò)的。比如我們寫(xiě)一個(gè)簡(jiǎn)單的測(cè) 試Bean如下:

          class TBean implements java.io.Serializable
          {
             
          private static final long serialVersionUID = 1945562032261336919L;
             
             
          private String name;

             
          public String getName()
              {
                 
          return name;
              }

             
          public void setName(String name)
              {
                 
          this.name = name;
              }
          }

              然后我們?cè)趍ain方法中加入如下幾行代碼:

          TBean tb = new TBean();
          tb.setName(
          "鐵木箱子");
          cache.add(
          "bean", tb);
          TBean tb1
          = (TBean)cache.get("bean");
          System.out.print(
          "name=" + tb1.getName());
          tb1.setName(
          "鐵木箱子_修改的");
          tb1
          = (TBean)cache.get("bean");
          System.out.print(
          "name=" + tb1.getName());

              我們首先把TBean的一個(gè)實(shí)例放入緩存中,然后再取出來(lái),并進(jìn)行名稱的修改,然后我們?cè)偃∵@個(gè)對(duì)象,我們?cè)倏雌涿Q,發(fā)現(xiàn)修改的對(duì)象并不是緩存中的對(duì) 象,而是通過(guò)序列化過(guò)來(lái)的一個(gè)實(shí)例對(duì)象,這樣我們就無(wú)須擔(dān)心對(duì)原生類的無(wú)意修改導(dǎo)致緩存數(shù)據(jù)失效了,呵呵~~看來(lái)我也是多此一想啊。所以這表明從緩存中獲 取的對(duì)象是存入對(duì)象的一個(gè)副本,對(duì)獲取對(duì)象的修改并不能真正的修改緩存中的數(shù)據(jù),而應(yīng)該使用其提供的replace等方法來(lái)進(jìn)行修改。

              以上是我在windows下對(duì)memcached的一點(diǎn)小學(xué)習(xí)和實(shí)踐,在以后的項(xiàng)目開(kāi)發(fā)過(guò)程中將會(huì)更深入的學(xué)習(xí)和應(yīng)用這一緩存工具,也希望和有興趣的同行一起討論學(xué)習(xí)該工具的使用~~ 微笑


          posted @ 2010-08-11 13:51 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(769) | 評(píng)論 (0)編輯 收藏

          轉(zhuǎn)載:http://www.aygfsteel.com/cnfree/archive/2008/06/12/207343.html

          最近的項(xiàng)目需要使用報(bào)表,因?yàn)槭荝CP應(yīng)用,所以選擇了Birt,用了一下,感覺(jué)還可以,就是網(wǎng)上資料少了點(diǎn),不過(guò)以前也研究過(guò)一些Eclipse相關(guān)技術(shù),這些都不重要了,找了SDK版本Debug,啥研究不出來(lái)?

          BIRT是一個(gè)Eclipse-based開(kāi)放源代碼報(bào)表系統(tǒng)。它主要是用在基于Java與J2EE的Web應(yīng)用程序上。BIRT主要由兩部分組成:一個(gè)是基于Eclipse的報(bào)表設(shè)計(jì)和一個(gè)可以加到你應(yīng)用服務(wù)的運(yùn)行期組件。BIRT同時(shí)也提供一個(gè)圖形報(bào)表制作引擎。

          官方主頁(yè):http://www.eclipse.org/birt
          官方BBS支持:http://www.actuatechina.com/forum2.html

          基本上來(lái)說(shuō)Birt功能還是很強(qiáng)大的,支持時(shí)下比較流行的WebService,Ajax技術(shù),既可用于Web,也可以用于桌面,更新也算穩(wěn)定,基本上遵循Eclipse的開(kāi)發(fā)步驟,一個(gè)一個(gè)大版本,同時(shí)支持腳本調(diào)用,debug開(kāi)發(fā)等等。唯一不足的就是中國(guó)的國(guó)情支持得還不夠完善,畢竟中國(guó)比較特殊,我以前給公司做黨務(wù)報(bào)表,要按照紙質(zhì)報(bào)表畫(huà),一分一毫都不能變差,那個(gè)變態(tài)呀,在電腦上畫(huà)報(bào)表還是拿尺子量。

          剛剛開(kāi)始用,慢慢研究,看了下Birt自帶的Example,的確是很強(qiáng)大,做得也很漂亮,自己試著創(chuàng)建一個(gè)報(bào)表也很簡(jiǎn)單,希望能夠比較快的上手吧。

          在網(wǎng)上找了一些資源:
          http://blogger.org.cn/blog/more.asp?name=sixsun&id=13933 BIRT 中文指南
          http://www.springside.org.cn/docs/reference/Birt.htm BIRT報(bào)表
          http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-birt/ Birt的IBM DW的中文教程
          http://download.eclipse.org/birt/downloads/demos/FirstReport/MyFirstReport.html Birt Flash Demo.
          posted @ 2009-02-02 09:31 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(379) | 評(píng)論 (0)編輯 收藏

           

          我們公司為每一個(gè)新進(jìn)來(lái)的員工指派了一個(gè)導(dǎo)師。這讓我想起了原來(lái)聽(tīng)過(guò)的微軟培訓(xùn),現(xiàn)簡(jiǎn)單的歸納了幾條,放上來(lái)供大家討論。

          1、首先微軟的導(dǎo)師選擇不是領(lǐng)導(dǎo)行政上指定的,而是學(xué)生選擇導(dǎo)師。
              在這里微軟強(qiáng)調(diào)的是:牛人才能成為導(dǎo)師。公司的人力資源系統(tǒng)有一模塊會(huì)把導(dǎo)師的特長(zhǎng)列出來(lái),以及原來(lái)被選擇為導(dǎo)師的次數(shù),還有歷界學(xué)生對(duì)其的評(píng)價(jià)。

              如果是新員工的話,基礎(chǔ)的流程常識(shí)之類的有培訓(xùn),具體到某一方面的技術(shù)的話,可以由你的上級(jí)指導(dǎo)你選擇。

          2、不是新人才能選擇導(dǎo)師,當(dāng)你換崗,換項(xiàng)目,反正對(duì)某個(gè)領(lǐng)域是新的時(shí)候,都可以選擇導(dǎo)師

          3、導(dǎo)師不會(huì)天天指導(dǎo)你,幫助你制定培訓(xùn)計(jì)劃。因?yàn)閷?dǎo)師的時(shí)間比你的時(shí)間寶貴的多

          方法是:

             1)學(xué)習(xí)、提高等等的計(jì)劃由你自己來(lái)完成。

             2)導(dǎo)師可以在郵件上花幾分鐘給你指導(dǎo)一下。

             3)導(dǎo)師可以在某個(gè)有空地時(shí)間找你談?wù)劊ɑ蚰慵s導(dǎo)師),但多是你請(qǐng)導(dǎo)師吃飯的時(shí)候。這樣飯也吃了,導(dǎo)師也當(dāng)了。

          4、(注意是大點(diǎn))導(dǎo)師指導(dǎo)你,對(duì)他是有好處的......

             1)提高影響力(微軟最注意的一點(diǎn)) 

             2)有了影響為,才有績(jī)效吧。

             3)有了影響力,以后的新人才會(huì)選擇你吧,以后的新人選擇你的越多,多到你的檔期安排不過(guò)來(lái),這才更牛吧!

           

          5、這對(duì)企業(yè)文化也有好處。

            1)文化影響共享,比強(qiáng)制,指派更有效些。 

            2)對(duì)新人、舊人都好,不會(huì)出現(xiàn)你有難,十方都會(huì),但都不支援你的情況

            3)不會(huì)出現(xiàn)研究成果,只保存在某個(gè)人的頭腦里的情況。節(jié)省資源

              特別說(shuō)明:這種考核對(duì)導(dǎo)師不考核。因?yàn)槭撬麑?dǎo)的作用,不是師的作用。師的考核是看他被選擇的次數(shù),學(xué)生對(duì)他的評(píng)價(jià)。這更客觀,真實(shí)。

          posted @ 2009-01-15 23:23 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(1468) | 評(píng)論 (0)編輯 收藏

          JAVA中,有六個(gè)不同的地方可以存儲(chǔ)數(shù)據(jù):
          1. 寄存器(register)。這是最快的存儲(chǔ)區(qū),因?yàn)樗挥诓煌谄渌鎯?chǔ)區(qū)的地方——處理器內(nèi)部。但是寄存器的數(shù)量極其有限,所以寄存器由編譯器根據(jù)需求進(jìn)行分配。你不能直接控制,也不能在程序中感覺(jué)到寄存器存在的任何跡象。
          2. 堆棧(stack)。位于通用RAM中,但通過(guò)它的“堆棧指針”可以從處理器哪里獲得支持。堆棧指針若向下移動(dòng),則分配新的內(nèi)存;若向上移動(dòng),則釋放那些內(nèi)存。這是一種快速有效的分配存儲(chǔ)方法,僅次于寄存器。創(chuàng)建程序時(shí)候,JAVA編譯器必須知道存儲(chǔ)在堆棧內(nèi)所有數(shù)據(jù)的確切大小和生命周期,因?yàn)樗仨毶上鄳?yīng)的代碼,以便上下移動(dòng)堆棧指針。這一約束限制了程序的靈活性,所以雖然某些JAVA數(shù)據(jù)存儲(chǔ)在堆棧中——特別是對(duì)象引用,但是JAVA對(duì)象不存儲(chǔ)其中。
          3. 堆(heap)。一種通用性的內(nèi)存池(也存在于RAM中),用于存放所以的JAVA對(duì) 象。堆不同于堆棧的好處是:編譯器不需要知道要從堆里分配多少存儲(chǔ)區(qū)域,也不必知道存儲(chǔ)的數(shù)據(jù)在堆里存活多長(zhǎng)時(shí)間。因此,在堆里分配存儲(chǔ)有很大的靈活性。 當(dāng)你需要?jiǎng)?chuàng)建一個(gè)對(duì)象的時(shí)候,只需要new寫(xiě)一行簡(jiǎn)單的代碼,當(dāng)執(zhí)行這行代碼時(shí),會(huì)自動(dòng)在堆里進(jìn)行存儲(chǔ)分配。當(dāng)然,為這種靈活性必須要付出相應(yīng)的代碼。用 堆進(jìn)行存儲(chǔ)分配比用堆棧進(jìn)行存儲(chǔ)存儲(chǔ)需要更多的時(shí)間。
          4. 靜態(tài)存儲(chǔ)(static storage)。這里的“靜態(tài)”是指“在固定的位置”。靜態(tài)存儲(chǔ)里存放程序運(yùn)行時(shí)一直存在的數(shù)據(jù)。你可用關(guān)鍵字static來(lái)標(biāo)識(shí)一個(gè)對(duì)象的特定元素是靜態(tài)的,但JAVA對(duì)象本身從來(lái)不會(huì)存放在靜態(tài)存儲(chǔ)空間里。
          5. 常量存儲(chǔ)(constant storage)。常量值通常直接存放在程序代碼內(nèi)部,這樣做是安全的,因?yàn)樗鼈冇肋h(yuǎn)不會(huì)被改變。有時(shí),在嵌入式系統(tǒng)中,常量本身會(huì)和其他部分分割離開(kāi),所以在這種情況下,可以選擇將其放在ROM中
          6. 非RAM存儲(chǔ)。如果數(shù)據(jù)完全存活于程序之外,那么它可以不受程序的任何控制,在程序沒(méi)有運(yùn)行時(shí)也可以存在。
          就速度來(lái)說(shuō),有如下關(guān)系:
              寄存器 < 堆棧 < 堆 < 其他

          『上面這段話摘取之《Thinking in Java》』

          在這里,主要要說(shuō)下堆與堆棧的關(guān)系:

                堆:堆是heap,是所謂的動(dòng)態(tài)內(nèi)存,其中的內(nèi)存在不需要時(shí)可以回收,以分配給新的內(nèi)存請(qǐng)求,其內(nèi)存中的數(shù)據(jù)是無(wú)序的,即先分配的和隨后分配的內(nèi)存并沒(méi)有 什么必然的位置關(guān)系,釋放時(shí)也可以沒(méi)有先后順序。一般由使用者自由分配,malloc分配的就是堆,需要手動(dòng)釋放。

                堆棧:就是STACK。實(shí)際上是只有一個(gè)出入口的隊(duì)列,即后進(jìn)先出(First     In     Last     Out),先分配的內(nèi)存必定后釋放。一般由,由系統(tǒng)自動(dòng)分配,存放存放函數(shù)的參數(shù)值,局部變量等,自動(dòng)清除。

          還有,堆是全局的,堆棧是每個(gè)函數(shù)進(jìn)入的時(shí)候分一小塊,函數(shù)返回的時(shí)候就釋放了,靜態(tài)和全局變量,new     得到的變量,都放在堆中,局部變量放在堆棧中,所以函數(shù)返回,局部變量就全沒(méi)了。

          其實(shí)在實(shí)際應(yīng)用中,堆棧多用來(lái)存儲(chǔ)方法的調(diào)用。而對(duì)則用于對(duì)象的存儲(chǔ)。

                 JAVA中的基本類型,其實(shí)需要特殊對(duì)待。因?yàn)椋?span id="wmqeeuq" class="hilite1">JAVA中,通過(guò)new創(chuàng)建的對(duì)象存儲(chǔ)在“堆”中,所以用new 創(chuàng)建一個(gè)小的、簡(jiǎn)單的變量,如基本類型等,往往不是很有效。因此,在JAVA中,對(duì)于這些類型,采用了與C、C++相同的方法。也就是說(shuō),不用new 來(lái)創(chuàng)建,而是創(chuàng)建一個(gè)并非是“引用”的“自動(dòng)”變量。這個(gè)變量擁有它的“值”,并置于堆棧中,因此更高效。
          posted @ 2008-11-16 00:57 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(1397) | 評(píng)論 (0)編輯 收藏

          前面講了用tomcat+axis來(lái)實(shí)現(xiàn)webservice,而網(wǎng)上對(duì)于weblogic+axis實(shí)現(xiàn)webservice卻不多,按照網(wǎng)上說(shuō)的做卻總是報(bào)錯(cuò),不成功,所以我經(jīng)過(guò)不停的試驗(yàn),終于配置成功了weblogic+axis

          首先我們下載一個(gè)weblogic8.1.3,jdk和axis的下載參照Tomcat+axis那片文章里的下載安裝和設(shè)置

          下載好后我們安裝weblogic,一直按下一步即可

          安裝完成后運(yùn)行Configuration Wizard來(lái)新建域配置,一直按下一步,直到輸入U(xiǎn)serName,Password and Description(我們這里都設(shè)置成weblogic),然后在按下一步直到完成

          然后我們將下載的axis壓縮包下的webapp目錄下的axis目錄拷貝到C:\bea\user_projects\domains\mydomain\applications下面

          由于axis中的一些jar包和weblogic中的有沖突,所以要修改C:\bea\user_projects\domains\mydomain\startWebLogic.cmd文件,優(yōu)先使用axis的jar,將其中的
          set CLASSPATH=%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%\jre\lib\rt.jar;%CLASSPATH%;%WL_HOME%\server\lib\webservices.jar
          改成
          set CLASSPATH=%AXISCLASSPATH%;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%\jre\lib\rt.jar;%WL_HOME%\server\lib\webservices.jar

          set CLASSPATH=%CLASSPATH%;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%\jre \lib\rt.jar;%WL_HOME%\server\lib\webservices.jar(這里必須保證將AXISCLASSPATH加入了 CLASSPATH環(huán)境變量中)
          保存運(yùn)行這個(gè)文件啟動(dòng)weblogic控制臺(tái),如下圖
          查看更多精彩圖片

          啟動(dòng)好之后打開(kāi)ie,在url中輸入http://localhost:7001/console,輸入用戶名和密碼進(jìn)入Weblogic Server Console
          查看更多精彩圖片

          點(diǎn)擊展開(kāi)部署節(jié)點(diǎn)--點(diǎn)擊WEB應(yīng)用程序模塊--然后點(diǎn)擊旁邊的部署新的新的應(yīng)用程序模塊,會(huì)出現(xiàn)選擇web應(yīng)用的窗口,如下圖
          查看更多精彩圖片

          選擇相應(yīng)目錄下的web應(yīng)用程序,我們選擇axis,如下圖
          查看更多精彩圖片

          點(diǎn)擊目標(biāo)模塊按鈕,接著在出現(xiàn)的窗口中點(diǎn)擊部署即可(這里我發(fā)現(xiàn)如果不在環(huán)境變量CLASSPATH中設(shè)置%AXISCLASSPATH%時(shí),部署將報(bào)錯(cuò))完成后如下圖
          查看更多精彩圖片

          這是我們可以點(diǎn)擊測(cè)試選項(xiàng)中的鏈接,也可以在ie中輸入http://localhost:7001/axis/,如果出現(xiàn)以下界面,說(shuō)明配置成功
          查看更多精彩圖片

          這時(shí)我們就可以按照tomcat+axis那篇文章所說(shuō)的發(fā)布web服務(wù)了

          遇到的問(wèn)題
          weblogic+axis的最大問(wèn)題是2者間jar包的沖突,客戶端調(diào)用web服務(wù)時(shí)會(huì)報(bào) NullPointerException錯(cuò)誤,網(wǎng)上都說(shuō)是axis的saaj.jar和weblogic的webservices.jar沖突,須將 saaj.jar加在webservices.jar前面,我按網(wǎng)上這么加了也沒(méi)用,后來(lái)我把整個(gè)AXISCLASSPATH都加到了最前面,就如我上面 所說(shuō)的那樣,嘿,他就好了,我暈俄,網(wǎng)上的人也不知道是怎么成功的

          還有一種說(shuō)法就是在web-inf目錄下加weblogic.xml,網(wǎng)上的人也沒(méi)說(shuō)要加到哪個(gè)web-inf下,我想想只有我的axis目錄下有web-inf吧,就加他下面了,weblogic.xml的內(nèi)容如下
          <!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">
          <weblogic-web-app>
           <container-descriptor>
            <prefer-web-inf-classes>true</prefer-web-inf-classes>
           </container-descriptor>
          </weblogic-web-app>
          這 樣也可以解決客戶端調(diào)用web服務(wù)時(shí)會(huì)報(bào)NullPointerException的錯(cuò)誤,但是我發(fā)現(xiàn)這樣做的后果是點(diǎn)擊axis的service的 wsdl時(shí)出現(xiàn)無(wú)法顯示頁(yè)面。所以經(jīng)過(guò)我不斷的調(diào)試,只有像我前面說(shuō)的那樣修改startWebLogic.cmd中的set CLASSPATH項(xiàng)應(yīng)該算是最完美的方法了,配這個(gè)東西的時(shí)候網(wǎng)上查了好久,都是千篇一律,說(shuō)得沒(méi)頭沒(méi)尾,所以說(shuō)還是得自己去實(shí)踐阿(實(shí)踐是檢驗(yàn)真理的 唯一標(biāo)準(zhǔn)嘛0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" alt="" align="absmiddle" border="0">)

          注:在部署好的web應(yīng)用程序的web-inf中加入weblogic.xml需要重新部署web應(yīng)用程序
                  修改了startWebLogic.cmd需重新執(zhí)行startWebLogic.cmd,以便修改起作用

          我在一個(gè)干凈的winxp sp2,JDK1.4.2.05,weblogic8.1.3的環(huán)境下部署了axis1.4,和同事在家遠(yuǎn)程調(diào)用獲得成功

          相關(guān)程序安裝目錄
          JDK        C:\j2sdk1.4.2_05
          weblogic  C:\bea
          axis1.4     C:\axis14(lib下有一些jar需另外當(dāng),老實(shí)說(shuō)我也不知道哪些起了作用,只是把網(wǎng)上所說(shuō)得涉及到的jar都找來(lái)了,嘿嘿)

          相關(guān)環(huán)境變量設(shè)置
          AXIS_HOME=C:\axis14
          AXIS_LIB=%AXIS_HOME%\lib
          AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\activation.jar;%AXIS_LIB%\xmlrpc-2.0.jar

          JAVA_HOME=C:\j2sdk1.4.2_05
          CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%AXISCLASSPATH%;

          Path前加了%JAVA_HOME%\bin

          posted @ 2008-11-13 00:35 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(6917) | 評(píng)論 (1)編輯 收藏

          根 據(jù)網(wǎng)上搜索到的一些例子做的時(shí)候碰到了挺多的問(wèn)題,經(jīng)過(guò)不懈的努力終于完成了這個(gè)webservice的例子,實(shí)際上axis的文檔上也寫(xiě)了一個(gè)例子,網(wǎng) 上的例子也大多都是照他上面所寫(xiě)的那樣,只是有些講的不算很詳細(xì),所以產(chǎn)生了不少錯(cuò)誤,小弟知識(shí)淺薄,如有寫(xiě)的不清楚地地方,還請(qǐng)見(jiàn)諒

          所需軟件
          tomcat        :http://tomcat.apache.org/index.html
          axis          :http://ws.apache.org/axis/
          jdk           :http://java.sun.com/javase/downloads/index.jsp
          jaf           :http://java.sun.com/products/javabeans/jaf/downloads/index.html
          xmlrpc        :http://ws.apache.org/xmlrpc

          XML解析器
          Xalan         :http://archive.apache.org/dist/xml/xalan-j/
          Xerces        :http://xml.apache.org/dist/xerces-j/

          本例講解axis定制發(fā)布

          本實(shí)例采用
          j2sdk1.4.2_05,tomcat5.0.28,axis1.4,jbuilder X / Eclipse3.2

          首先將axis解壓至相應(yīng)目錄,如d:\下,安裝tomcat至c:\tomcat5,安裝jdk至c:\ j2sdk1.4.2_05
          然后將d:\axis\webapp目錄下的axis目錄copy至c:\tomcat5\webapps目錄下

          設(shè)置axis的環(huán)境變量

          AXIS_HOME=d:\axis

          AXIS_LIB=%AXIS_HOME%\lib

          AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar;%AXIS_LIB%\wsdl4j-1.5.1.jar;%AXIS_LIB%\activation.jar;%AXIS_LIB%\xmlrpc-2.0.jar

           

          (xml-apis.jar, xercesImpl.jar屬于Xerces或Xalan, activation.jar屬于jaf, xmlrpc-2.0.jar屬于xmlrpc)

          1. 配置完成后啟動(dòng)tomcat,在瀏覽器中鍵入http://localhost:8080/axis,將顯示如下畫(huà)面

          查看更多精彩圖片

          2.在C:\Tomcat5\webapps\axis\WEB-INF目錄下建立一個(gè)src目錄,用于存放源程序
          接著編寫(xiě)服務(wù)端程序server.AxisReturn
          package server;
          public class AxisReturn {
              public String ReturnMsg(String servicesName) {
                return "Axis Return: "+ servicesName;
              }
          }
          在 此我們利用了Jbuilder X作為我們java程序的開(kāi)發(fā)工具,利用Jbuilder新建工程中的Project for Existing Code將C:\Tomcat5\webapps\axis\WEB-INF下的程序及目錄導(dǎo)入作為Jbuilder的一個(gè)工程來(lái)操作

          查看更多精彩圖片
          編譯AxisReturn程序,Jbuilder將會(huì)把編譯后的class文件自存放在C:\Tomcat5\webapps\axis\WEB-INF\classes\server目錄下

          3.編寫(xiě)wsdd文件,此處命名為deploy.wsdd,其內(nèi)容為

          <deployment xmlns=http://xml.apache.org/axis/wsdd/
                        xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
          <service name="AxisReturn" provider="java:RPC">
              <parameter name="className" value="server.AxisReturn"/>
              <parameter name="allowedMethods" value="*"/>
          </service>
          </deployment>


          每個(gè)service就代表服務(wù)端的一個(gè)程序,如有多個(gè)可繼續(xù)添加service,相關(guān)參數(shù)請(qǐng)查閱axis文檔
          此處的deployment代表發(fā)布服務(wù),如改為undeployment則為撤銷服務(wù)

          4.發(fā)布服務(wù)
          打開(kāi)windows的命令窗口,轉(zhuǎn)到wsdd文件的存放目錄下,此處為C:\Tomcat5\webapps\axis\WEB-INF\src\server
          在命令窗口中鍵入
          java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd

          如果成功將顯示<Admin>Done processing</Admin>
          如失敗,則檢查AXISCLASSPATH是否設(shè)置正確,tomcat端口是否為默認(rèn)的8080
          在這里有一個(gè)問(wèn)題需注意,不管是在axis目錄下還是其他虛擬目錄下,如直接執(zhí)行這條命令,都將在axis的目錄下發(fā)布service,如果想發(fā)布在其他的目錄下,如pscsaxis,則應(yīng)執(zhí)行
          java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/pscsaxis/services/AdminService deploy.wsdd

          -cp表示在AXISCLASSPATH環(huán)境變量中檢索org.apache.axis.client.AdminClient方法

          5.生成client stub文件
          在命令窗口中將目錄轉(zhuǎn)至C:\Tomcat5\webapps\axis\WEB-INF\classes
          然后執(zhí)行
          java -cp %AXISCLASSPATH% org.apache.axis.wsdl.Java2WSDL -oAxisReturn.wsdl -lhttp://localhost:8080/axis/services/AxisReturn -nAxisReturn server.AxisReturn

          將會(huì)在C:\Tomcat5\webapps\pscsaxis\WEB-INF\classes下生成AxisReturn.wsdl文件
          接著在執(zhí)行
          java -cp %AXISCLASSPATH% org.apache.axis.wsdl.WSDL2Java AxisReturn.wsdl -p client

          將會(huì)在C:\Tomcat5\webapps\axis\WEB-INF\classes\client目錄下生成四個(gè)java文件
          AxisReturn_PortType.java
          AxisReturnService.java
          AxisReturnServiceLocator.java
          AxisReturnSoapBindingStub.java
          將這四個(gè)文件剪切至C:\Tomcat5\webapps\pscsaxis\WEB-INF\src\client目錄下,并編譯

          6.編寫(xiě)客戶端
          利用生成client stub文件編寫(xiě)

          package client;
          public class ClientAxisReturn {
              public static void main(String args[]) {
                try {
                  AxisReturnService service = new client.AxisReturnServiceLocator();
                  client.AxisReturn_PortType client = service.getAxisReturn();
                  String retValue = client.returnMsg("BaoSteel");
                  System.out.println(retValue);
                }
                catch (Exception e) {
                  System.err.println("Execution failed. Exception: " + e);
                }
              }
          }

          編寫(xiě)完后,編譯運(yùn)行即可得到返回結(jié)果
          如需傳入多個(gè)參數(shù),需在String retValue = client.returnMsg("BaoSteel");這句中增加參數(shù),如
          String retValue = client.returnMsg("BaoSteel","PSCS_IMS");
          相應(yīng)的服務(wù)端也要更改,如
          package server;
          public class AxisReturn {
              public String ReturnMsg(String servicesName,String serviceID) {
                return "Axis Return: "+ servicesName+ serviceID;
              }
          }

          利用發(fā)布服務(wù)的wsdl的URL編寫(xiě)
          package client;
          import org.apache.axis.AxisFault;
          import org.apache.axis.client.Call;
          import org.apache.axis.client.Service;
          import javax.xml.rpc.ParameterMode;
          import javax.xml.rpc.encoding.XMLType;
          public class ClientAxisReturnWsdl {
              public static void main(String args[]) throws Exception{
                String endPoint =
                  
          http://190.2.63.239:8080/pscsaxis/services/AxisReturn?wsdl;
                Service service = new Service();
                Call call = (Call) service.createCall();
                Object result;
                try {
                  call.setTargetEndpointAddress(new java.net.URL(endPoint));
                  call.setOperationName("ReturnMsg");
                  call.addParameter("OP1", XMLType.XSD_STRING, ParameterMode.IN);
                  call.setReturnType(XMLType.XSD_STRING);
                  result = (Object) call.invoke(new Object[] {"BaoSteel"});
                }
                catch (AxisFault fault) {
                  result = "Error is: " + fault.toString();
                }
                System.out.println(result);
              }
          }

          編寫(xiě)完后,編譯運(yùn)行即可得到返回結(jié)果
          如許增加參數(shù),則需添加語(yǔ)句
          call.addParameter("OP1", XMLType.XSD_STRING, ParameterMode.IN);
          將參數(shù)名OP1改為其他,如OP2
          在result = (Object) call.invoke(new Object[] {" BaoSteel "});這句中增加參數(shù),如
          result = (Object) call.invoke(new Object[] {" BaoSteel "," PSCS_IMS "});
          相應(yīng)的服務(wù)端也要更改,如
          package server;
          public class AxisReturn {
              public String ReturnMsg(String servicesName,String serviceID) {
                return "Axis Return: "+ servicesName+ serviceID;
              }
          }

          ★在這里,我們的服務(wù)端只有一個(gè)方法供我們調(diào)用,如果我們需要調(diào)用多個(gè)服務(wù)端的方法,則可在服務(wù)端中加入其他方法,如我們?cè)谠黾右粋€(gè)xxMsg

          package server;
          public class AxisReturn {
              public String ReturnMsg(String servicesName,String systemID) {
                return "Axis Return: "+ str+servicesName+systemID;
              }
              public String xxMsg(String serviceName,String systemID) {
              return "XX Return: "+ str+serviceName+systemID;
          }
          }

          ★修改完后將其編譯,并將其注銷后重新發(fā)布,反之需要重起tomcat,否則服務(wù)將不被更新
          ★利用生成client stub文件編寫(xiě)的客戶端程序,還需重新生成client stub文件,并將其編譯,在客戶端程序中調(diào)用其相應(yīng)得方法即可

          SOAPMonitor的配置

          發(fā) 布了Web服務(wù)以后,如何觀察請(qǐng)求和響應(yīng)數(shù)據(jù)呢?記錄運(yùn)行日志是一種傳統(tǒng)且有效的方法,但對(duì)于調(diào)試程序來(lái)講還不夠方便和直觀。值得欣慰的是,Axis為我 們提供了在客戶端觀察SOAP請(qǐng)求和響應(yīng)流數(shù)據(jù)的工具SoapMonitor,經(jīng)過(guò)適當(dāng)配置后,可以實(shí)時(shí)地觀察到Web服務(wù)的SOAP請(qǐng)求和響應(yīng)數(shù)據(jù)。 SoapMonitor是一個(gè)Java Applet程序,通過(guò)瀏覽器下載到客戶端運(yùn)行。下面就介紹SoapMonitor的配置和使用方法。

          在C:\Tomcat5\webapps\axis的目錄下有一個(gè)SOAPMonitorApplet.java的程序,axis默認(rèn)沒(méi)有給我們編譯,我們需要自己進(jìn)行編譯

          打開(kāi)windows命令窗口,轉(zhuǎn)到C:\Tomcat5\webapps\axis目錄下,執(zhí)行
          javac -classpath %AXIS_HOME%\lib\axis.jar SOAPMonitorApplet.java

          編譯完成后需要發(fā)布服務(wù),我們需要建立一個(gè)wsdd文件deploy-monitor.wsdd,內(nèi)容如下

          <deployment xmlns=http://xml.apache.org/axis/wsdd/
                xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
              <handler name="soapmonitor"
                  type="java:org.apache.axis.handlers.SOAPMonitorHandler">
                <parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/>
                <parameter name="namespace" value="http://tempuri.org/wsdl/2001/12/SOAPMonitorService-impl.wsdl"/>
                <parameter name="serviceName" value="SOAPMonitorService"/>
                <parameter name="portName" value="Demo"/>
              </handler>
              <service name="SOAPMonitorService" provider="java:RPC">
                <parameter name="allowedMethods" value="publishMessage"/>
                <parameter name="className" value="org.apache.axis.monitor.SOAPMonitorService"/>
                <parameter name="scope" value="Application"/>
              </service>
          </deployment>

          需要注意的是紅色的那句語(yǔ)句,如果是在我們自己的web應(yīng)用目錄下的話需改成自己的目錄。
          建立完成后執(zhí)行命令進(jìn)行發(fā)布
          java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService deploy-monitor.wsdd

          發(fā)布SOAPMonitor服務(wù)后,還要對(duì)被監(jiān)測(cè)的Web服務(wù)進(jìn)行配置。方法是先注銷該Web服務(wù),然后修改該服務(wù)對(duì)應(yīng)的WSDD文件,在其中增加請(qǐng)求流和響應(yīng)流的配置,否則是觀測(cè)不到SOAP請(qǐng)求和響應(yīng)流的。以我們上面的程序?yàn)槔瑢eploy.wsdd修改為

           

          <deployment xmlns=http://xml.apache.org/axis/wsdd/
                        xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
          <service name="AxisReturn" provider="java:RPC">
                <requestFlow>
                  <handler type="soapmonitor"/>
                </requestFlow>
                <responseFlow>
                  <handler type="soapmonitor"/>
                </responseFlow>
              <parameter name="className" value="server.AxisReturn"/>
              <parameter name="allowedMethods" value="*"/>
          </service>
          </deployment>


          增加了
               <requestFlow>
                  <handler type="soapmonitor"/>
                </requestFlow>
                <responseFlow>
                  <handler type="soapmonitor"/>
                </responseFlow>
          這兩段

          然后我們通過(guò)點(diǎn)擊http://localhost:8080/axis/主頁(yè)上的SOAPMonitor或直接訪問(wèn)http://localhost:8080/axis/SOAPMonitor,點(diǎn)擊start或stop啟動(dòng)或停止監(jiān)控,然后我們運(yùn)行客戶端程序,SOAPMonitor會(huì)監(jiān)控到請(qǐng)求和響應(yīng)流,如下圖

          查看更多精彩圖片

          在 這里,我們需要注意一個(gè)配置問(wèn)題,如果tomcat下有多個(gè)axis應(yīng)用,設(shè)置了多個(gè)SOAPmonitor,我們則需要更改SOAPmonitor的端 口(axis默認(rèn)配置的是5001),否則會(huì)產(chǎn)生沖突,運(yùn)行SOAPmonitor時(shí)會(huì)無(wú)法啟動(dòng),提示the soap monitor is unable to communcate with the server,解決方法如下:

          打開(kāi)C:\Tomcat5\webapps\axis\WEB-INF目錄下的web.xml,找到

          <servlet>
                <servlet-name>SOAPMonitorService</servlet-name>
                <display-name>SOAPMonitorService</display-name>
                <servlet-class>
                    org.apache.axis.monitor.SOAPMonitorService
                </servlet-class>
                <init-param>
                  <param-name>SOAPMonitorPort</param-name>
                  <param-value>5001</param-value>
                </init-param>
                <load-on-startup>100</load-on-startup>
          </servlet>

          這段,將其中的5001改成5002,依此類推

          總結(jié):
          盡量將發(fā)布websrrvice的文件夾和axis分開(kāi)放置
          建立多個(gè)axis應(yīng)用時(shí),應(yīng)注意一些端口的設(shè)置,命令的參數(shù)設(shè)置以及一些命令執(zhí)行的路徑設(shè)置等,否則會(huì)產(chǎn)生一些錯(cuò)誤,如ClassNotFound,service發(fā)布錯(cuò)誤等的錯(cuò)誤

           

          server-config.wsdd

          <?xml version="1.0" encoding="UTF-8"?>
          <deployment xmlns:java="      xmlns:handler="      xmlns="      xmlns:xsi="      name="defaultClientConfig" xsi:type="deployment">
               <globalConfiguration>
                   <parameter name="disablePrettyXML" value="true"/>
                   <parameter name="dotNetSoapEncFix" value="true"/>
                   <parameter name="enableNamespacePrefixOptimization" value="false"/>
                   <requestFlow>
                       <handler type="java:org.apache.axis.handlers.JWSHandler">
                           <parameter name="scope" value="session"/>
                       </handler>
                       <handler type="java:org.apache.axis.handlers.JWSHandler">
                           <parameter name="scope" value="request"/>
                           <parameter name="extension" value=".jwr"/>
                       </handler>
                   </requestFlow>
               </globalConfiguration>
               <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
               <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
               <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>

              <service name="CallcenterWebServices" provider="java:RPC" style="rpc" use="encoded">
                   <parameter name="scope" value="Request"/>
                   <parameter name="className" value="com.isw2.ebay.callcenter.axis.CallcenterWebServices"/>
                   <parameter name="allowedMethods" value="getStatus,getCsrBean,setStatus,createCase,showContactRecord,getWorkload"/>
                   
              <beanMapping qname="myNS:CsrBean" xmlns:myNS="urn:CsrBean"
              languageSpecificType="java:com.isw2.ebay.callcenter.axis.CsrBean" />
             <beanMapping qname="myNS:ContactRecordBean" xmlns:myNS="urn:ContactRecordBean"
              languageSpecificType="java:com.isw2.ebay.callcenter.axis.ContactRecordBean" />  
             <beanMapping qname="myNS:DisputeContactRecord" xmlns:myNS="urn:DisputeContactRecord"
              languageSpecificType="java:com.isw2.ebay.callcenter.axis.DisputeContactRecord" />
             <beanMapping qname="myNS:WorkloadNumberBean" xmlns:myNS="urn:WorkloadNumberBean"
              languageSpecificType="java:com.isw2.ebay.callcenter.axis.WorkloadNumberBean" />  
            
               </service>
              
               <service name="AdminService" provider="java:MSG">
                   <parameter name="allowedMethods" value="AdminService"/>
                   <parameter name="enableRemoteAdmin" value="false"/>
                   <parameter name="className" value="org.apache.axis.utils.Admin"/>
                   <namespace>http://xml.apache.org/axis/wsdd/</namespace>
               </service>
               <service name="Version" provider="java:RPC">
                   <parameter name="allowedMethods" value="getVersion"/>
                   <parameter name="className" value="org.apache.axis.Version"/>
               </service>
               <transport name="http">
                   <parameter name="qs:list" value="org.apache.axis.transport.http.QSListHandler"/>
                   <parameter name="qs:method" value="org.apache.axis.transport.http.QSMethodHandler"/>
                   <parameter name="qs:wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
                   <requestFlow>
                       <handler type="URLMapper"/>
                       <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
                   </requestFlow>
               </transport>
               <transport name="local">
                   <responseFlow>
                       <handler type="LocalResponder"/>
                   </responseFlow>
               </transport>
          </deployment>
          posted @ 2008-11-13 00:33 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險(xiǎn),融鷹之神在山巔. 閱讀(4974) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 嘉禾县| 宜兰市| 尼木县| 竹溪县| 诏安县| 莫力| 漾濞| 迁安市| 龙岩市| 榆林市| 门头沟区| 高要市| 石阡县| 天镇县| 舒城县| 盱眙县| 平阴县| 巴青县| 宜城市| 河南省| 宁国市| 万全县| 互助| 延长县| 梅州市| 古田县| 张家口市| 钟祥市| 综艺| 开阳县| 浙江省| 陆良县| 高清| 安义县| 澄迈县| 岗巴县| 高尔夫| 馆陶县| 襄城县| 光山县| 宁津县|