#
總有那么一些代碼,在測試環境下,是不能輕易被調用的。
比如:
1)發送系統任務郵件到客戶郵箱,可能一不小心,就把測試郵件發送給了真實客戶的郵箱里;
2)調用跨公司的系統接口,而對方系統沒有測試環境,每調用一次接口,就會在對方系統產生垃圾數據;
3)調用的代碼可能需要大量的cpu運算,占用大量的內存空間,消耗大量的資源;
等等。。。
為了解決這樣的需求,
1)在代碼中,到處充斥著這樣的代碼:
1 if(在測試環境下) {
2 打印日志;
3 } else {
4 調用真實的業務邏輯;
5 }
于是乎,需要到處維護這樣的代碼,一旦增加此類需求,就需要編寫同樣的代碼
2)部分懶惰的程序員,連這樣的if...else...也不愿意寫,僅僅在注釋中說明下在測試環境中調用方法的危害性。
于是,在測試階段,一旦和測試部門溝通不足,導致代碼還是經常被調用到,如果是在作壓力,性能測試,那么危害性可想而已。
曾發生過,壓力測試某個功能,結果把大量的測試郵件,發送給了客戶,影響很差。
那么,如何解決這樣的需求場景呢?
沒錯,采用proxy模式,可以搞定。考慮到現在很多企業都使用Spring作為IOC容器,本文就簡單介紹,如何采用spring aop來解決問題。
以發送郵件的需求作為虛擬場景。
現在有個Service,專門負責郵件的發送。
1. MyService.java
1 public class MyService {
2 public void sendMailSafely() {
3 System.out.println("send mail successfully.");
4 }
5 }
如果這個sendMailSafely被客戶端調用,那么毫無疑問,郵件不管任何環境下,都會被成功發送。
需要有個方法攔截器,對這個方法做攔截。
2. MyInterceptor.java
1 public class MyInterceptor implements MethodInterceptor {
2
3 private boolean isProduction = false;
4
5 @Override
6 public Object invoke(MethodInvocation invocation) throws Throwable {
7 if (!isProduction) {
8 System.out.println("is production environment.do nothing
");
9 return null;
10 }
11 return invocation.proceed();
12 }
13
14 public void setProduction(boolean isProduction) {
15 this.isProduction = isProduction;
16 }
17
18 }
這個攔截器,根據配置文件的參數isProduction判斷是否在正式環境,如果是在測試環境,對方法做攔截,僅僅打印log,不真實調用業務邏輯。
如何讓sendMailSafely()方法被此攔截器做攔截,所以通過spring配置文件,配置一個advisor,通知對以Safely結尾的方法做攔截
3. application.xml
1 <bean id="safetyAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" scope="singleton">
2 <property name="advice">
3 <ref local="myInterceptor" />
4 </property>
5 <property name="patterns">
6 <list>
7 <value>.*Safely</value>
8 </list>
9 </property>
10 </bean>
附上application.xml的全部內容
1 <beans default-autowire="byName">
2
3 <!-- service實例 -->
4 <bean id="myService" class="cn.zeroall.javalab.aop.MyService" scope="singleton" />
5
6 <!-- 方法攔截器 -->
7 <bean id="myInterceptor" class="cn.zeroall.javalab.aop.MyInterceptor" scope="singleton">
8 <property name="production" value="false" />
9 </bean>
10
11 <!-- 通知者 -->
12 <bean id="safetyAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" scope="singleton">
13 <property name="advice">
14 <ref local="myInterceptor" />
15 </property>
16 <property name="patterns">
17 <list>
18 <value>.*Safely</value>
19 </list>
20 </property>
21 </bean>
22
23 <!-- myService代理類 -->
24 <bean id="safetyService" class="org.springframework.aop.framework.ProxyFactoryBean" scope="singleton">
25 <property name="interceptorNames">
26 <list>
27 <value>safetyAdvisor</value>
28 </list>
29 </property>
30 <property name="targetName" value="myService" />
31 </bean>
32
33 </beans>
寫一個Client類來做演示。
4. Client.java
1 public class Client {
2
3 private ApplicationContext ctx = new ClassPathXmlApplicationContext(
4 "cn/zeroall/javalab/aop/application.xml");;
5
6 public static void main(String[] args) {
7 Client c = new Client();
8 c.sendMail();
9 c.sendMailSafety();
10 }
11
12 public void sendMail() {
13 MyService myService = (MyService) ctx.getBean("myService");
14 myService.sendMailSafely();
15 }
16
17 public void sendMailSafety() {
18 MyService myService = (MyService) ctx.getBean("safetyService");
19 myService.sendMailSafely();
20 }
21
22 }
大家可以看看最終輸出的結果內容。
一直來,我都不會濫用AOP,尤其反感使用AOP來寫業務邏輯內容,但是對于這類非業務邏輯需求,采用spring aop技術那是剛剛好啊。
最后,附上全部代碼文件(使用maven構建)。
演示代碼
逐漸地,發覺數據訂正成為了我工作的一部分;
逐漸地,發覺一天有四個小時的時間在數據訂正上的日子越來越多;
逐漸地,發覺一天僅僅只有兩個小時投入到編碼的日子也頻繁起來;
逐漸地,發覺我面向的客戶也不僅僅是PD,測試部門,客服、銷售、銷售支持也成為了我的服務對象。
我不是做技術支持的,但是客服、銷售、銷售支持的咨詢以及提交數據訂正的申請打擾卻影響到了
我正常的工作,只能利用晚上加班的時候,去完成一天的編碼工作。
為什么會有那么多數據訂正發生?
合理的數據訂正,一般發生于下面的兩種可能:
1)系統程序存在bug,那么毫無疑問,只能作bug fix工作,然后集中進行一次數據訂正操作;
2)業務部門,由于不小心,操作失誤等原因,產生錯誤數據。這種情形發生的比較少,一般由這種原因導致的錯誤數據,
我這邊收到銷售支持提交的數據訂正申請,都會馬上協助完成訂正工作。
但是,現在越來越多的項目,開發時間嚴重被壓縮,在項目過程中,
1)業務邏輯本身就考慮不周全,沒有考慮和牽連系統的關系,導致需求邏輯就存在問題;
2)為了減少開發人日,把本來該交給系統實現的需求,卻考慮人工來完成,增加了人為誤操作的發生概率;
3)為了減少開發成本,對接口行為不做邏輯驗證處理,而接口錯誤參數,往往增加了系統錯誤數據的產生;
4)開發時間緊急,開發人員在不熟悉原有系統的基礎上,就進行新功能的開發;過于過程式的開發;
系統、代碼設計的時間過少;不敢做重夠,等等,導致代碼可讀性很差,維護性不強,易出bug。
。。。。。。
由這些原因而造成的bug,形成的錯誤數據,我厭惡為其做數據訂正:
不在源頭做控制,一旦出了問題,才考慮到手工數據訂正來暫時性的解決問題,這絕對不是一個好的項目團隊的做法。
我們一直在宣稱要做百年的企業,但是我們目前的系統,又能維持幾年呢?
最具魅力圣火傳遞城市人氣榜
在msn網站(
http://msn.ynet.com/eventmsnc.jsp?eid=38162866&cd=china)上有最具魔力圣火傳遞城市人氣榜投票。身為紹興人,看到自己的家鄉排名考后,心有不甘,又看到溫州等城市有人采用自動投票工具不斷給自己刷票,于是乎,花費晚上一個小時的時間,用java(選用apache httpclient組件開發,比較方便。)也寫了一個自動投票小軟件,給紹興投票。
本想在自己的機器上跑程序,但是考慮到不可能7*24小時運行,于是在網上找到一個jsp免費空間(
http://eatj.com),把投票工具部署成web app形式,放到eatj網上,借用人家的服務器,替紹興投票 :)
通過
http://stone2083.s43.eatj.com/web/vote?action=query這個url,可以查看目前所有城市投票總數。
http://eatj.com,一直來提供了免費空間的服務,作為java初學者,可以拿這個空間練練手,或者作為小作品展示的地方。
20 MB space;
提供mysql服務;
提供tomcat5/tomcat6選擇;
jdk5/jdk6選擇
對于免費來說,已經是很好的服務了。
(但是對于免費空間,每隔6個小時,它會中斷服務,需要手工啟動下,這個有點惡心。)
今天參加了
第二屆阿里巴巴網絡俠客行大會。
由于最近加班比較多,早上貪睡不起,錯過了俠客行上午場的會議,據說林斌—谷歌中國工程院副院長在講話中介紹了google的一些技術,沒聽頗為可惜。
下午場的會議,我選擇是“
分會場三 開放服務框架/Open Service framework”
第一場會議是林昊—淘寶網平臺架構師帶來的OSGI分享。
OSGI確實是一個很好的概念,很好的實現了模塊動態化管理。試想一下,以后軟件的功能可以像硬件一樣,動態化插拔,那是多爽的一件事情。
Eclipse3版本,就是base on osgi的一個成功案例,用過eclipse開發的同學,一定對eclipse的plugin管理機制很心動,可以動態增加,刪除插件。Eeclipse本身只提供了一個平臺,功能都可以通過插件的方式增加。并且可以按照開發者的需求,增加插件。
據說jdk7版本,就會在語言級別上支持osgi,這則消息也是振奮人心。----目前jdk只有class(類),package(包)的概念,卻沒有module(模塊)的概念,所謂模塊化開發,僅僅是人工分割package的方式來實現。
概念是好,但是針對目前以有的功能,如何不傷筋動骨的完成base on osgi或者run on osgi,仍然是一個很大的一個問題。這也是很多企業對osgi僅僅停留在觀望態度上的一個原因。
第二場會議是黃柳青—普元首席科學家、CTO分享的SCA--感覺他老人家英語說得比中文還好。
之前,我對SCA沒有任何的了解,甚至連概念都沒有聽過。正好趁此分享機會,對SCA做個概念性的了解。
SCA(Service Component Architecture)
這玩意,究其本質,其實是對代碼層面做了可視化組件的封裝。他的概念是,把每個邏輯都看成是一個Component(組件/構件),然后根據不同的業務需要,去配置不同的Component,以及component之間的業務流。
其實,這個概念是很好的,尤其結合他天生的搭檔OSGI,可以使得所有的開發者眼前一亮。
試想一下,以后有個系統(Base on OSGI),業務流程中,其中有個業務需求發生了變化,那么只需要開發者開發一個新的component,并且把原先的component動態uninstall,并且把新的component動態install,系統可以在運行期,就完成需求的變動。多爽。
概念是好,但是是否能流行,還需要時間的考驗。
第三場會議是 袁紅崗—金蝶中間件首席架構師 介紹
OperaMask,只是自己做這塊內容沒有興趣,就換了會場,去了分
會場一 開放平臺/Open Platform。
第三場會議趙進—/阿里軟件首席架構師 介紹
Alisoft SAAS Platform
這小子年紀輕輕就當上了阿里軟件的首席架構師,只有26歲,對他充滿了敬意。努力向他學習。
這場分享,感覺只是很膚淺的介紹了阿里軟件saas的平臺。過程中更多的是講了saas的概念和阿里軟件saas的一些模式,沒有涉及到技術細節層面的內容,比較失望。
SAAS的概念近年來逐漸流行起來。如何構建SAAS平臺系統,是我最關注的點。比如:
如何發布開放API接口,
如何管理開放API接口,
如何對開放API進行測試,
如何確保開放API接口的安全性,
API接口采用什么技術調用,SAAS Platform是否統一規范對API的調用,采用什么方式傳輸數據,等等。
這些細節,都沒有在這次分享中涉及到,太失望了。
整體來說,這次網絡俠客行,還是讓自己增長了不少見識,學到了不少技術。
希望阿里巴巴在接下去的幾屆中,能越辦越好,更希望在技術交流會上,能出現更多國內技術的分享,期待國內軟件業的發展 :)
eclipse安裝插件的方式,常見的一般有3種:
1)把插件一股腦兒都扔到$ECLIPSE_HOME/plugins下面;
這是最方便的一種安裝方式了,但是如果插件一多,就很難管理。如果想停用某幾個插件,嘿嘿,沒轍。。。
2)利用eclipse的manage configuration功能;
eclipse-->help-->software updates-->manage configuration
在這里,添加extension location(外部擴展點),把插件的地址一個一個添加進來。
這也是我一度使用的方法。可以比較方便的管理插件。
但是唯一不爽的,就是一旦eclipse重裝,你就需要把這些擴展點一個一個添加進來,比較麻煩。
3)采用link方式安裝插件
這是我目前最喜歡的一種安裝eclipse plugins的方式。
在$ECLIPSE_HOME下,建立一個links目錄。
links目錄下,創建link文件(文件名和后綴可以隨意指定),比如findbugs.link,內容如下:
path=/usr/software/eclipse_ext/plugins/findbugs
path后面跟的就是插件的地址。
需要注意的是,插件比如采用標準的目錄結構
eclipse
|------plugins
|------features
采用link的方式,不但方便插件的管理,而且當eclipse重裝的時候,只要把links目錄copy到新的$ECLIPSE_HOME下即可。
ubuntu下,thunderbird是我首選的郵件管理工具(類似于windows下的outlook)。
用起來蠻爽,唯一不足就是沒有日歷功能,不能接受來自outlook的事件邀請。
幸好,thunderbird有個日歷插件,
Lightning。剛好滿足我的需求。建議使用。
放一張截圖上來:
firefox是我首選的瀏覽器,但是啟動速度實在不敢恭維。
從網上找了一些文章,修改了幾個參數。
前提:地址欄輸入 about:config 進入參數配置頁面
首選項名稱:config.trim_on_minimize,
類型:布爾
鍵值:true
作用:最小化時釋放內存
備注:據說只在windows下有效(怪不得,我在linux下確實感覺沒什么效果)
首選項名稱:browser.sessionhistory.max_total_viewers
類型:整數
鍵值:0 (當然,你也可以設置成你需要緩存的頁面數)
作用:前進/后退 功能,用于緩存頁面數量
首選項名稱:network.http.pipelining
類型:布爾
鍵值:true
作用:在http連接中,使用pipelining功能。據說能加速瀏覽速度
首選項名稱:network.http.pipelining.maxrequests
類型:整數
鍵值:8 (據說上限是8)
作用:是一個實驗性功能,加速瀏覽網站的速度。需要站點的支持。
首選項名稱:nglayout.initialpaint.delay
類型:整數
鍵值:100 (默認值是250)單位是毫秒
作用:ff收到response后等待n毫秒,進行頁面渲染
首選項名稱:network.dns.disableIPv6
類型:布爾
鍵值:true
作用:禁用ip6功能(好像跟優化沒什么關系)
首選項名稱:browser.tabs.loadDivertedInBackground
類型:布爾
鍵值:true
作用:打開新tab時,停留在當前頁面(跟優化沒關系,只是符合我的瀏覽習慣)
關于這些首選項的意義,具體可以訪問:http://kb.mozillazine.org/network.http.pipelining 得到相應參數的意義。
最后,做個廣告,效果還是蠻明顯的。推薦使用 :)
今天在一次會議中,有朋友問我,如何避免資源被迅雷等工具多線程下載?
確實,一些中小企業站點,尤其是個人站點,由于沒有過多資金,服務器承受不了大的壓力,站點提供的資源,一旦被迅雷等多線程工具下載,
對服務器的壓力還是蠻客觀的。
那么有什么辦法避免多線程下載呢?其實最簡單的辦法,就是服務端根本就不要提供Content-Length值。試想一下,如果多線程下載工具得不到文件總大小值,如何分配去分配每個線程需要下載的量呢?不得已,只能通過單線程下載了。
以http下載為例,我寫了一個提供下載的servlet,由于不返回Content-Length值(只返回了
ContentType值),這個serlvet返回的流,只能單線程下載。
public class Download extends HttpServlet {
private static final long serialVersionUID = 8401962046132204450L;
private static final String FILE_PATH = "/home/jones/tmp/sample.zip";
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/octet-stream");
OutputStream out = resp.getOutputStream();
FileInputStream in = new FileInputStream(FILE_PATH);
int readLength = 0;
byte[] cache = new byte[1024];
while ((readLength = in.read(cache)) != -1) {
out.write(cache, 0, readLength);
}
in.close();
out.flush();
out.close();
}
}
同樣的道理,只要配置服務器不要返回Content-Length值,那么就可以有效避免多線程下載了。
摘要: CGlib概述:
cglib(Code Generation Library)是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。
cglib封裝了asm,可以在運行期動態生成新的class。
cglib用于AOP,jdk中的proxy必須基于接口,cglib卻沒有這個限制。
CGlib應用:
以一個實例在簡單介紹下cglib的應用。
我...
閱讀全文
常用的GC算法:
1)標記非活動對象
--何為非活動對象,通俗的講,就是無引用的對象。
- 追蹤root對象算法: 深度追蹤root對象,將heap中所有被引用到的root做標志,所有未被標志的對象視為非活動對象,所占用的空間視為非活動內存。
2)清理非活動對象
- 方法:將內存分為兩個區域(from space和to space)。所有的對象分配內存都分配到from space。在清理非活動對象階段,把所有標志為活動的對象,copy到to space,之后清楚from space空間。然后互換from sapce和to space的身份。既原先的from space變成to sapce,原先的to space變成from space。每次清理,重復上述過程。
- 優點:copy算法不理會非活動對象,copy數量僅僅取決為活動對象的數量。并且在copy的同時,整理了heap空間,即,to space的空間使用始終是連續的,內存使用效率得到提高。
- 缺點:劃分from space和to space,內存的使用率是1/2。
- Compaction算法:
- 方法:在清理非活動對象階段,刪除非活動對象占用內存,并且把活動對象向heap的底部移動,直到所有的活動對象被移到heap的一側。
- 優點:無須劃分from sapce和to space,提高內存的使用率。并且compaction后的內存空間也是連續分配的。
- 缺點:該算法相對比較復雜。
sun jdk gc介紹:
在減少gc之前,先來看看來自IBM的一組統計數據:
98%的java對象,在創建之后不久就變成了非活動對象;只有2%的對象,會在長時間一直處于活動狀態。
如果能對這兩種對象區分對象,那么會提交GC的效率。在sun jdk gc中(具體的說,是在jdk1.4之后的版本),提出了不同生命周期的GC策略。
- young generation:
- 生命周期很短的對象,歸為young generation。由于生命周期很短,這部分對象在gc的時候,很大部分的對象已經成為非活動對象。因此針對young generation的對象,采用copy算法,只需要將少量的存活下來的對象copy到to space。存活的對象數量越少,那么copy算法的效率越高。
- young generation的gc稱為minor gc。經過數次minor gc,依舊存活的對象,將被移出young generation,移到tenured generation(下面將會介紹)
- young generation分為:
- eden:每當對象創建的時候,總是被分配在這個區域
- survivor1:copy算法中的from space
- survivor2:copy算法中的to sapce (備注:其中survivor1和survivor2的身份在每次minor gc后被互換)
- minor gc的時候,會把eden+survivor1(2)的對象copy到survivor2(1)去。
- tenured generation:
- 生命周期較常的對象,歸入到tenured generation。一般是經過多次minor gc,還 依舊存活的對象,將移入到tenured generation。(當然,在minor gc中如果存活的對象的超過survivor的容量,放不下的對象會直接移入到tenured generation)
- tenured generation的gc稱為major gc,就是通常說的full gc。
- 采用compactiion算法。由于tenured generaion區域比較大,而且通常對象生命周期都比較常,compaction需要一定時間。所以這部分的gc時間比較長。
- minor gc可能引發full gc。當eden+from space的空間大于tenured generation區的剩余空間時,會引發full gc。這是悲觀算法,要確保eden+from space的對象如果都存活,必須有足夠的tenured generation空間存放這些對象。
- Permanet Generation:
- 該區域比較穩定,主要用于存放classloader信息,比如類信息和method信息。
- 對于spring hibernate這些需要動態類型支持的框架,這個區域需要足夠的空間。
這部分內容相對比較理論,可以結合jstat,jmap等命令(當然也可以使用jconsole,jprofile,gciewer等工具),觀察jdk gc的情況。