qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          Java防止SQL注入的幾個途徑

           JavaSQL注入,最簡單的辦法是杜絕SQL拼接,SQL注入攻擊能得逞是因為在原有SQL語句中加入了新的邏輯,如果使用PreparedStatement來代替Statement來執(zhí)行SQL語句,其后只是輸入?yún)?shù),SQL注入攻擊手段將無效,這是因為PreparedStatement不允許在不同的插入時間改變查詢的邏輯結(jié)構(gòu),大部分的SQL注入已經(jīng)擋住了,在WEB層我們可以過濾用戶的輸入來防止SQL注入比如用Filter來過濾全局的表單參數(shù)。

        1. import java.io.IOException;  
        2. import java.util.Iterator;  
        3. import javax.servlet.Filter;  
        4. import javax.servlet.FilterChain;  
        5. import javax.servlet.FilterConfig;  
        6. import javax.servlet.ServletException;  
        7. import javax.servlet.ServletRequest;  
        8. import javax.servlet.ServletResponse;  
        9. import javax.servlet.http.HttpServletRequest;  
        10. import javax.servlet.http.HttpServletResponse;  
        11. /** 
        12. * 通過Filter過濾器來防SQL注入攻擊 
        13. * 
        14. */ 
        15. public class SQLFilter implements Filter {  
        16. private String inj_str = "'|and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|; |or|-|+|,";  
        17. protected FilterConfig filterConfig = null;  
        18. /** 
        19. * Should a character encoding specified by the client be ignored? 
        20. */ 
        21. protected boolean ignore = true;  
        22. public void init(FilterConfig config) throws ServletException {  
        23. this.filterConfig = config;  
        24. this.inj_str = filterConfig.getInitParameter("keywords");  
        25. }  
        26. public void doFilter(ServletRequest request, ServletResponse response,  
        27. FilterChain chain) throws IOException, ServletException {  
        28. HttpServletRequest req = (HttpServletRequest)request;  
        29. HttpServletResponse res = (HttpServletResponse)response;  
        30. Iterator values = req.getParameterMap().values().iterator();//獲取所有的表單參數(shù) 
        31. while(values.hasNext()){  
        32. String[] value = (String[])values.next();  
        33. for(int i = 0;i < value.length;i++){  
        34. if(sql_inj(value[i])){  
        35. //TODO這里發(fā)現(xiàn)sql注入代碼的業(yè)務(wù)邏輯代碼 
        36. return;  
        37. }  
        38. }  
        39. }  
        40. chain.doFilter(request, response);  
        41. }  
        42. public boolean sql_inj(String str)  
        43. {  
        44. String[] inj_stra=inj_str.split("\\|");  
        45. for (int i=0 ; i < inj_stra.length ; i++ )  
        46. {  
        47. if (str.indexOf(" "+inj_stra[i]+" ")>=0)  
        48. {  
        49. return true;  
        50. }  
        51. }  
        52. return false;  
        53. }  
        54. }
        55.   也可以單獨在需要防范SQL注入的JavaBean的字段上過濾:

        56. /** 
        57. * 防止sql注入 
        58. * 
        59. * @param sql 
        60. * @return 
        61. */ 
        62. public static String TransactSQLInjection(String sql) {  
        63. return sql.replaceAll(".*([';]+|(--)+).*"" ");  
        64. }
        65. posted @ 2012-01-04 10:46 順其自然EVO 閱讀(236) | 評論 (0)編輯 收藏

          Java并發(fā)編程:守護線程

          Java中有兩類線程:用戶線程(UserThread)、守護線程(DaemonThread)。

            所謂守護線程,是指在程序運行的時候在后臺提供一種通用服務(wù)的線程,比如垃圾回收線程就是一個很稱職的守護者,并且這種線程并不屬于程序中不可或缺的部分。因此,當(dāng)所有的非守護線程結(jié)束時,程序也就終止了,同時會殺死進程中的所有守護線程。反過來說,只要任何非守護線程還在運行,程序就不會終止。

            用戶線程和守護線程兩者幾乎沒有區(qū)別,唯一的不同之處就在于虛擬機的離開:如果用戶線程已經(jīng)全部退出運行了,只剩下守護線程存在了,虛擬機也就退出了。因為沒有了被守護者,守護線程也就沒有工作可做了,也就沒有繼續(xù)運行程序的必要了。

            將線程轉(zhuǎn)換為守護線程可以通過調(diào)用Thread對象的setDaemon(true)方法來實現(xiàn)。在使用守護線程時需要注意一下幾點:

            (1)thread.setDaemon(true)必須在thread.start()之前設(shè)置,否則會跑出一個IllegalThreadStateException異常。你不能把正在運行的常規(guī)線程設(shè)置為守護線程。

            (2)在Daemon線程中產(chǎn)生的新線程也是Daemon的。

            (3)守護線程應(yīng)該永遠不去訪問固有資源,如文件、數(shù)據(jù)庫,因為它會在任何時候甚至在一個操作的中間發(fā)生中斷。

            代碼示例:

          1. import java.util.concurrent.TimeUnit;  
          2. /** 
          3. * 守護線程 
          4. */ 
          5. public class Daemons {  
          6. /** 
          7. * @param args 
          8. * @throws InterruptedException  
          9. */ 
          10. public static void main(String[] args) throws InterruptedException {  
          11. Thread d = new Thread(new Daemon());  
          12. d.setDaemon(true); //必須在啟動線程前調(diào)用 
          13. d.start();  
          14. System.out.println("d.isDaemon() = " + d.isDaemon() + ".");  
          15. TimeUnit.SECONDS.sleep(1);  
          16. }  
          17. }  
          18. class DaemonSpawn implements Runnable {  
          19. public void run() {  
          20. while (true) {  
          21. Thread.yield();  
          22. }  
          23. }  
          24. }  
          25. class Daemon implements Runnable {  
          26. private Thread[] t = new Thread[10];  
          27. public void run() {  
          28. for (int i=0; i<t.length; i++) {  
          29. t[i] = new Thread(new DaemonSpawn());  
          30. t[i].start();  
          31. System.out.println("DaemonSpawn " + i + " started.");  
          32. }  
          33. for (int i=0; i<t.length; i++) {  
          34. System.out.println("t[" + i + "].isDaemon() = " +  
          35. t[i].isDaemon() + ".");  
          36. }  
          37. while (true) {  
          38. Thread.yield();  
          39. }  
          40. }  
          41. }

            運行結(jié)果:

          1. d.isDaemon() = true.  
          2. DaemonSpawn 0 started.  
          3. DaemonSpawn 1 started.  
          4. DaemonSpawn 2 started.  
          5. DaemonSpawn 3 started.  
          6. DaemonSpawn 4 started.  
          7. DaemonSpawn 5 started.  
          8. DaemonSpawn 6 started.  
          9. DaemonSpawn 7 started.  
          10. DaemonSpawn 8 started.  
          11. DaemonSpawn 9 started.  
          12. t[0].isDaemon() = true.  
          13. t[1].isDaemon() = true.  
          14. t[2].isDaemon() = true.  
          15. t[3].isDaemon() = true.  
          16. t[4].isDaemon() = true.  
          17. t[5].isDaemon() = true.  
          18. t[6].isDaemon() = true.  
          19. t[7].isDaemon() = true.  
          20. t[8].isDaemon() = true.  
          21. t[9].isDaemon() = true.

           以上結(jié)果說明了守護線程中產(chǎn)生的新線程也是守護線程。

            如果將mian函數(shù)中的TimeUnit.SECONDS.sleep(1);注釋掉,運行結(jié)果如下:

          1. d.isDaemon() = true.  
          2. DaemonSpawn 0 started.  
          3. DaemonSpawn 1 started.  
          4. DaemonSpawn 2 started.  
          5. DaemonSpawn 3 started.  
          6. DaemonSpawn 4 started.  
          7. DaemonSpawn 5 started.  
          8. DaemonSpawn 6 started.  
          9. DaemonSpawn 7 started.  
          10. DaemonSpawn 8 started.  
          11. DaemonSpawn 9 started.

            以上結(jié)果說明了如果用戶線程已經(jīng)全部退出運行了,只剩下守護線程存在了,虛擬機也就退出了。下面的例子也說明了這個問題。

            代碼示例:

          1. import java.util.concurrent.TimeUnit;  
          2. /**  
          3. * Finally shoud be always run ?  
          4. */  
          5. public class DaemonsDontRunFinally {  
          6. /**  
          7. * @param args  
          8. */  
          9. public static void main(String[] args) {  
          10. Thread t = new Thread(new ADaemon());  
          11. t.setDaemon(true);  
          12. t.start();  
          13. }  
          14. }  
          15. class ADaemon implements Runnable {  
          16. public void run() {  
          17. try {  
          18. System.out.println("start ADaemon...");  
          19. TimeUnit.SECONDS.sleep(1);  
          20. } catch (InterruptedException e) {  
          21. System.out.println("Exiting via InterruptedException");  
          22. } finally {  
          23. System.out.println("This shoud be always run ?");  
          24. }  
          25. }  
          26. }

            運行結(jié)果:

            start ADaemon...

            如果將main函數(shù)中的t.setDaemon(true);注釋掉,運行結(jié)果如下:

            start ADaemon...

            This shoud be always run ?



          posted @ 2011-12-31 10:34 順其自然EVO 閱讀(201) | 評論 (0)編輯 收藏

          五種方法教你搭建Linux學(xué)習(xí)環(huán)境(三)

            前兩篇文章中已經(jīng)介紹了三種搭建Linux學(xué)習(xí)環(huán)境的方法,本文將介紹第四、第五種方法。

            第四種方法:在Windows系統(tǒng)中,用VNC工具軟件登錄到遠程服務(wù)器上的 Linux桌面。這種遠程登錄的方式,一方面可以用于遠程配置和維護Linux服務(wù)器,另一方面也可以用它來在真實的環(huán)境中學(xué)習(xí)各種Linux命令。 VNC(Virtual Network Computing,虛擬網(wǎng)絡(luò)計算機)軟件主要由兩部分組成,VNC server和VNC viewer。用戶要先將VNC server安裝在被控端的計算機上才能在主控端執(zhí)行VNC viewer控制被控端。

            VNC server與VNC viewer支持多種操作系統(tǒng),如Unix、Linux、Solaris、Windows和MacOS,因此可將VNC server 及VNC viewer分別安裝在不同的操作系統(tǒng)中進行控制。如果目前操作的主控端計算機沒有安裝VNC viewer,也可以通過一般的網(wǎng)頁瀏覽器來控制被控端。VNC的主要工作原理是在服務(wù)器端運行 VNC server服務(wù),然后在客戶端就可以遠程連接服務(wù)器端的桌面了。下面就介紹,在主控端的計算機操作系統(tǒng)為Win 7,被控端服務(wù)器的操作系統(tǒng)為64位RedHat Enterprise Linux 5.3上的VNC viewer與VNC server的安裝與配置步驟:

            1、在服務(wù)器端的RedHat中安裝VNC server,安裝包的文件名為“vnc-4.1.2-14.el5.x86_64.rpm”,此文件在光盤中的路徑為“RedHat Enterprise Linux 5.3 for 64-bit AMD64 AND INTEL 64_Installation\Server”。

            也可以打開網(wǎng)站http://rpm.pbone.net/,在如下所示的對話框中輸入“vnc-4.1.2-14.el5”,然后點擊SEARCH,也可以找到相應(yīng)的RPM安裝包,下載下來即可,如圖9所示。

          圖9 下載RPM包網(wǎng)站圖示

            2、安裝VNC server的rpm包。可以把安裝包“vnc-4.1.2-14.el5.x86_64.rpm”拷貝到\root\.vnc目錄下,然后在此目錄下直接運行安裝命令即可,安裝過程的顯示提示如下所示:

            [root@localhost .vnc]# rpm -ivh vnc-4.1.2-14.el5.x86_64.rpm

            warning: vnc-4.1.2-14.el5.x86_64.rpm: Header V3 DSA signature: NOKEY, key ID 37017186

            Preparing...  ########################################### [100%]

            package vnc-4.1.2-14.el5.x86_64 is already installed

            3、編輯.vnc目錄下的xstartup文件。可以使用vi編輯器進行編輯,命令為“[root@localhost .vnc]#vi xstartup”,打開xstartup文件后在鍵盤上點擊“A”字母鍵,使VI編輯器進入編輯狀態(tài)。然后屏蔽掉最后一行,即在最后一行的前面加上符號 “#”,變成“#twm &”,然后再在最下面加上“gnome-session &”。完成后,點擊“Esc”鍵,再點擊“:”鍵,然后輸入“wq”回車,即保存退出。加上“gnome-session &”是為了能夠在Windows系統(tǒng)上顯示Linxu的桌面,否則只能看到一個“終端”的命令行窗口。

            4、設(shè)置登錄用戶。如果上面的安裝成功,在目錄/etc/sysconfig/下會有一個vncservers文件。用VI編輯器編輯vncservers文件,在最后加上VNCSERVERS="1:root",保存后退出。

            5、設(shè)置VNC遠程登錄密碼。運行命令“[root@localhost ~]# vncpasswd”,然后按提示設(shè)置好遠程登錄的密碼。然后執(zhí)行命令“[root@localhost ~]#vncserver”,會有如下顯示:

            New 'localhost.localdomain:1 (root)' desktop is localhost.localdomain:1

            Starting applications specified in /root/.vnc/xstartup

            Log file is /root/.vnc/localhost.localdomain:1.log

          這里需要注意的是,上面的輸出“localhost.localdomain:1 (root)”,說明在用瀏覽器遠程登錄Linux系統(tǒng)時,在瀏覽器地址欄中要輸入的地址為“Linux服務(wù)器的IP地址:5801”,如果上面的輸出為 “2(root)”,則在瀏覽器地址欄中要輸入的命令就為“5802”。如果連接成功,輸入密碼后就可以遠程控制Linux桌面了。

          圖10 用VNC Viewer軟件登錄的界面圖示

            6、用瀏覽器登錄Linux桌面的畫質(zhì)可能不太好,可以在Windows下安裝VNC Viewer工具軟件直接連接。首先要在Windows系統(tǒng)中安裝RealVNC軟件,如“vnc-4.1.3-x86_win32.exe”。安裝完成后,打開“開始”菜單里的RealVNC ---> VNC Viewer 4 ---> Run VNC Viewer,在VNC Viewer的地址欄中輸入“Linux服務(wù)器的IP地址:1”,如果上面的輸出為“2”,則在VNC Viewer的地址欄中的IP地址后面把“:1”換成“:2”,如圖10所示,點擊“OK”,然后輸入在上面“5”中設(shè)置的密碼,就可成功連接到遠程 Linux桌面,猶如在本地操作Linux系統(tǒng)一樣,如圖11所示。

          圖11 用VNC Viewer遠程登錄到Linux桌面圖示

            若在VNC Viewer的“Server”地址欄中輸入的IP地址后面所接的端口號,不是“localhost.localdomain:1 (root)”中的“1”,而是寫成了其它的數(shù)字,那可能只能進入到Linux系統(tǒng)的終端命令行模式,而進入不到圖形化的桌面模式。

            下面將介紹第五種:用SSH方式登錄到遠程服務(wù)器的Linux系統(tǒng)中。其實和SSH登錄方式非常相像的還有Telnet登錄,但因為Telnet登錄的用戶名和密碼,以及在配置管理當(dāng)中所使用的Linux命令,都是以明文方式傳送,沒有任何安全措施,所以目前它基本上已經(jīng)被SSH的登錄方式所取代。SSH服務(wù)在Linux下的設(shè)置非常簡單。下面就簡要地介紹下SSH服務(wù)的設(shè)置與登錄的步驟:

            1、SSH服務(wù)的安裝狀態(tài)。此服務(wù)默認是安裝的,但也可以通過以下命令來查詢在Linux系統(tǒng)中是否安裝了SSH服務(wù)。

            [root@localhost ~]# rpm -qa | grep ssh

            openssh-clients-4.3p2-29.el5

            openssh-4.3p2-29.el5

            openssh-askpass-4.3p2-29.el5

            openssh-server-4.3p2-29.el5

            若出現(xiàn)以上的顯示結(jié)果,則表示此Linux系統(tǒng)已經(jīng)安裝了SSH服務(wù)。輸出內(nèi)容的第一行顯示的是SSH的客戶端軟件包;第二行顯示的是SSH的核心文件;第三行表示SSH支持對話框的顯示,是一個基于X系統(tǒng)的密碼診斷工具;第四行是SSH的服務(wù)器軟件包。

          2、SSH服務(wù)的運行狀態(tài)。此服務(wù)默認也是自動運行的,但也可以通過以下命令來查詢SSH服務(wù)的運行狀態(tài)。

            [root@localhost ~]#service sshd status

            openssh-daemon (pid  5340) is running...

            若出現(xiàn)以上的顯示結(jié)果,則表示此Linux系統(tǒng)的SSH服務(wù)已經(jīng)運行。其中,“sshd”是SSH服務(wù)的守護進程名稱。若SSH服務(wù)沒有啟動的話,則運行命令[root@localhost ~]#service sshd restart即可。

          圖12 用SecureCRT以SSH方式登錄的參數(shù)設(shè)置

            3、用SSH進行遠程登錄的設(shè)置。若是在Windows系統(tǒng)中,沒有自帶的SSH客戶端,可以在網(wǎng)上下載支持SSH遠程登錄的圖形化工具軟件,常用的有 SecureCRT、Putty等。如圖12所示,是用SecureCRT進行遠程SSH登錄的設(shè)置。在“Hostname”中輸入SSH服務(wù)器的IP地址,“Port”中輸入22,“Username”中輸入用戶名。然后根據(jù)提示,輸入密碼,就可以連接到遠程的SSH服務(wù)器。若是在Linux系統(tǒng)中進行遠程的SSH登錄,就可以在Linux的終端窗口的命令提示符下,直接使用命令#ssh 192.168.1.2進行遠程登錄即可。

            4、SSH的配置文件。SSH有兩個主要的配置文件,一個為客戶端的配置文件ssh_config,一個為服務(wù)器端的配置文件sshd_config。這兩個配置文件都位于目錄/etc/ssh下。用VI編輯器就可以對這兩個配置文件進行詳細的配置和修改,以便用戶在使用SSH時能滿足一些特殊的要求。

            總結(jié)

            以上五種搭建Linux學(xué)習(xí)環(huán)境的模式,主要是根據(jù)實際情況,選擇最適合自己的,它們之間無好壞之分。通常Linux高手對Linux的架構(gòu)、命令都很熟悉,更習(xí)慣使用SSH的方式。這種方式在配置和管理服務(wù)器時更靈活,功能更強大。而對于網(wǎng)速帶寬有保證的地方,同時又有充足的硬件服務(wù)器資源的話,采用第一種模式是最好的。

            第二種和第三種模式主要適用有個人固定的筆記本或臺式機電腦,但網(wǎng)絡(luò)帶寬卻不能保證的用戶。這時,在個人電腦或虛擬機上安裝Linux,也是不錯的選擇。第四種和第一種有相似之處,都要求網(wǎng)絡(luò)帶寬要有保證,但第四種沒有第一種使用起來更方便。第四種還必須在電腦上安裝RealVNC軟件才行,若不安裝的話使用瀏覽器和JAVA程序控制遠程的Linux,效果并不是很好。

          相關(guān)鏈接:

          五種方法教你搭建Linux學(xué)習(xí)環(huán)境(一)

          五種方法教你搭建Linux學(xué)習(xí)環(huán)境(二)

          posted @ 2011-12-31 00:18 順其自然EVO 閱讀(561) | 評論 (0)編輯 收藏

          SQL Server的“警報”問題應(yīng)該如何解決

          問:SQL Server的警報問題應(yīng)該如何解決?

            答:具體的解決方法請參考下文 :

            ◆ 檢查你是否使用了最新的Sql Server service pack。因為在最新的Sql Server service pack中已經(jīng)修補了很多Sql Server使用警告(Alerts)的漏洞。應(yīng)該確保在你的系統(tǒng)中已經(jīng)安裝了最新的Sql Server service pack補丁包。

            ◆ 檢查SqlServerAgent服務(wù)的帳戶是否作為成員運行在域用戶群組(Domain User Group)下。LocalSystem帳戶沒有訪問網(wǎng)絡(luò)的權(quán)限,所以,如果你需要將事件記錄在其他運行有Windows NT或Windows 2000機器上的應(yīng)用程序日志上,或者你的作業(yè)(jobs)需要跨網(wǎng)絡(luò)的資源,或者你需要通過e-mail或者pagers通知操作者,這時候,你就需要將SalServerAgent服務(wù)的帳戶設(shè)置在域用戶群組(Domain User Group)下作為它的成員。

            ◆ 如果所定義的警報都沒有觸發(fā),檢查SqlServerAgent和EventLog服務(wù)是否都在運行。如果你需要讓你定義的警報被觸發(fā),這些服務(wù)必須被開啟。所以,如果這些服務(wù)沒有被運行的話,請運行它們。

            ◆ 如果有某個警報沒有被觸發(fā),請確保它們是否被啟用。警報可以被啟用或禁用,為了檢查一個警報是否被啟用,你應(yīng)該做以下這些步驟:

            1、運行Sql Server Enterprise Manager

            2、請打開服務(wù)器群組,然后打開某個服務(wù)器

            3、請打開管理(Management),然后再打開Sql Server Agent

            4、雙擊合適的警報以查看這個警報是否被啟用了

            5、檢查警報的歷史值以確定警報最后工作的日期和時間

            為了檢查一個警報的歷史值,你應(yīng)該做以下這些事情:

            1、運行Sql Server Enterprise Manager

            2、請打開服務(wù)器群組,然后打開某個服務(wù)器

            3、請打開管理(Management),然后再打開Sql Server Agent

            4、雙擊合適的警報以查看警報的歷史值

            5、核對每20秒維護的計數(shù)器值

            因為Sql Server Agent每20秒間隔維護一個性能計數(shù)器,如果發(fā)現(xiàn)這個性能計數(shù)器只有幾秒鐘(少于20秒)才維護一次,那么極有可能你的這個警報將不會被觸發(fā)。

            6、檢查Sql Server錯誤日志、Sql Server Agent錯誤日志以及Windows NT和Windows 2000的應(yīng)用程序日志,以獲得有關(guān)錯誤描述的更多詳細信息。仔細檢查核對當(dāng)產(chǎn)生警報失敗事件時,被記錄在Sql Server錯誤日志、Sql Server Agent錯誤日志以及Windows NT和Windows 2000的應(yīng)用程序日志中的日期和時間以及對錯誤的描述能幫助你分析產(chǎn)生警報失敗事件的原因。

            7、假如警報被觸發(fā)了,但是這時候操作員卻沒有收到任何通知,請嘗試手動使用“e-mail”,“pager”或者用“net send”將信息發(fā)送給操作員。在很多情況下,可能你輸入了一個錯%C。

          posted @ 2011-12-31 00:16 順其自然EVO 閱讀(178) | 評論 (0)編輯 收藏

          深入Java虛擬機之虛擬機體系結(jié)構(gòu)

           工作以來,代碼越寫越多,程序也越來越臃腫,效率越來越低,對于我這樣一個追求完美的程序員來說,這是絕對不被允許的,于是除了不斷優(yōu)化程序結(jié)構(gòu)外,內(nèi)存優(yōu)化和性能調(diào)優(yōu)就成了我慣用的“伎倆”。

            要對Java程序進行內(nèi)存優(yōu)化和性能調(diào)優(yōu),不了解虛擬機的內(nèi)部原理(或者叫規(guī)范更嚴謹一點)是肯定不行的,這里推薦一本好書《深入Java虛擬機(第二版)》(Bill Venners著,曹曉剛 蔣靖 譯,實際上本文正是作者閱讀本書之后,對Java虛擬機的個人理解闡述)。當(dāng)然了,了解Java虛擬機的好處并不僅限于上述兩點好處。從更深一點的技術(shù)層面上看,了解Java虛擬機的規(guī)范和實現(xiàn),將更加有助于我們編寫高效、穩(wěn)定的Java代碼。比如,假如了解Java虛擬機的內(nèi)存模型,了解虛擬機的內(nèi)存回收機制,那么我們就不會過分依賴它,而會在需要的時候顯式的"釋放內(nèi)存"(Java代碼不能顯式釋放內(nèi)存,但是可以通過釋放對象引用告知垃圾回收器回收該對象需要被回收),以降低不必要的內(nèi)存消耗;假如我們了解Java棧的工作原理,那么我們就可以通過減少遞歸層數(shù),減少循環(huán)次數(shù)來降低堆棧溢出的風(fēng)險。可能對于應(yīng)用開發(fā)人員來說,可能不會直接去涉及這些Java虛擬機底層實現(xiàn)的工作,但是了解這些背景知識,或多或少,都會對我們寫的程序產(chǎn)生潛移默化的好的影響。

            本篇文章,將簡明扼要的說明Java虛擬機的體系結(jié)構(gòu)和內(nèi)存模型,如有用詞不妥或解釋不準確之處,請不吝指正,深感榮幸!

            Java 虛擬機體系結(jié)構(gòu)

            類裝載子系統(tǒng)

            Java虛擬機有兩種類裝載器,分別是啟動類裝載器和用戶自定義裝載器。

            通類裝載子系統(tǒng)通過類的全限定名(包名和類名,網(wǎng)絡(luò)裝載還包括 URL)將 Class 裝載進運行時數(shù)據(jù)區(qū)。對于每一個被裝載的類型,Java虛擬機都會創(chuàng)建一個java.lang.Class類的實例來代表該類型,該實例被放在內(nèi)存中的堆區(qū),而裝載的類型信息則位于方法區(qū),這一點和所有其他對象都是一樣的。

            類裝載子系統(tǒng)在裝載一個類型前,除了要定位和導(dǎo)入對應(yīng)的二進制class文件外,還要驗證導(dǎo)入類的正確性,為類變量分配并初始化內(nèi)存,以及解析符號引用為直接引用,這些動作嚴格按照以下順序進行:

            1)裝載——查找并裝載類型的二進制數(shù)據(jù);

            2)連接——執(zhí)行驗證,準備以及解析(可選)

            3)驗證 確保被導(dǎo)入類型的正確性

            4)準備 為類變量分配內(nèi)存,并將其初始化為默認值

            5)解析 把類型中的符號引用轉(zhuǎn)換為直接應(yīng)用

            方法區(qū)

            對于每一個被類裝載子系統(tǒng)裝載的類型,虛擬機都會保存下列數(shù)據(jù)到方法區(qū):

            ◆  類型的全限定名

            ◆ 類型超類的全限定名(java.lang.Object沒有超類)

            ◆ 類型是類類型還是接口類型

            ◆ 類型的訪問修飾符

            ◆ 任何直接超接口的全限定名有序列表

           除了上述基本類型信息,還將保存如下信息:

            ◆ 類型的常量池

            ◆ 字段信息(包括字段名、字段類型、字段修飾符)

            ◆ 方法信息(包括方法名、返回類型、參數(shù)的數(shù)量和類型、方法修飾符,如果方法不是抽象和本地的,還將保存方法的字節(jié)碼、操作數(shù)棧和該方法棧幀中的局部變量區(qū)的大小和異常表)

            ◆ 常量以外的所有類變量(其實就是類的靜態(tài)變量,因為靜態(tài)變量是所有實例共享的,且與類型直接相關(guān),所以他們是類一級的變量,作為類的成員被保存在方法區(qū))

            一個到類ClassLoader的引用

        66. //返回的就是剛才保存的ClassLoader引用   
        67. String.class.getClassLoader();
        68.   一個到Class類的引用

        69. //將返回剛才保存的Class類的引用   
        70. String.class;
        71.   注意,方法區(qū)也是可以被垃圾回收器回收的。

            堆

            Java程序在運行時創(chuàng)建的所有類實例或數(shù)組都放在同一個堆中,而每一個Java虛擬機也是有一個對空間,所有線程共享一個堆(這就是一個多線程的Java程序會產(chǎn)生對象訪問的同步問題的原因了)。

            由于每一種Java虛擬機都有對虛擬機規(guī)范的不同實現(xiàn),所以我們可能不知道每一種Java虛擬機在堆中是以何種形式表示對象實例的,不過我們可以通過下面這可能的實現(xiàn)來一窺端倪:


            程序計數(shù)器

            對于運行中的Java程序而言,每一個線程都有自己的PC(程序計數(shù)器)寄存器,它是在該線程啟動時創(chuàng)建的,大小為一個字長,用來保存需要被執(zhí)行的下一行代碼的位置。

            Java棧

            每一個線程都有一個Java棧,以棧幀為單位保存線程的運行狀態(tài)。虛擬機對Java棧的操作有兩種:壓棧和出棧,二者都已幀為單位。棧幀保存了傳入?yún)?shù)、局部變量、中間運算結(jié)果等數(shù)據(jù),在方法完成時被彈出,然后釋放。

            看一下兩個局部變量相加時棧幀的內(nèi)存快照

            本地方法棧

            這是 Java 調(diào)用操作系統(tǒng)本地庫的地方,用來實現(xiàn) JNI(Java Native Interface,Java 本地接口)

            執(zhí)行引擎

            Java虛擬機的核心,控制裝入 Java 字節(jié)碼并解析;對于運行中的Java程序而言,每一個線程都是一個獨立的虛擬機執(zhí)行引擎的實例,從線程生命周期的開始到結(jié)束,他要么在執(zhí)行字節(jié)碼,要么在執(zhí)行本地方法。

            本地接口

            連接了本地方法棧和操作系統(tǒng)庫。

            注:文中所有提到“Java虛擬機”的地方都是指“JavaEE和JavaSE平臺的Java虛擬機規(guī)范”。

          posted @ 2011-12-31 00:15 順其自然EVO 閱讀(176) | 評論 (0)編輯 收藏

          從Java的角度理解Ext的extend

               摘要: 在Java中,我們在實現(xiàn)繼承的時候存在下面幾個事實:  1、準備兩個類,他們用extends關(guān)鍵字鏈接起來  2、如果超類沒有默認構(gòu)造函數(shù),需要在子類構(gòu)造函數(shù)中顯式的super并傳參,如果都是默認構(gòu)造函數(shù)也可以super,不super虛擬機是自動的  3、子類可追加,覆蓋,重載方法,子類可以有自己的私有屬性,他們在子類構(gòu)造函數(shù)中被構(gòu)造  4、字段是數(shù)據(jù),方法在代碼區(qū),和類建立方法表,同一個類的對象...  閱讀全文

          posted @ 2011-12-29 13:26 順其自然EVO 閱讀(205) | 評論 (0)編輯 收藏

          組織beta測試的十二個最高秘訣

          組織beta測試的十二個最高秘訣

           這篇文章中,作者以誠懇的筆觸將自己在組織beta測試的親身感受與大家分享,希望可以給廣大開發(fā)人員帶來幫助。

            下面是一些關(guān)于如何組織一次軟件的beta測試的秘訣。需要注意的是,這里所說的“軟件”指的是面向大量用戶的軟件,也就是我所稱的“包裝盒軟件(注:“包裝盒軟件”指的是在商場中上架銷售、有獨立包裝、外面用熱收縮塑料膜密封的軟件商品。)”(shrink-wrap)。這些秘訣對商業(yè)項目和開源項目都適用。不管你開發(fā)軟件的目的是獲得報酬,還是獲得眼球效應(yīng),或是提高在同行中的知名度,都可以參考這些秘訣。但是,我關(guān)注的只是有大量用戶的軟件產(chǎn)品,而不是公司內(nèi)部的IT項目。

            1. 開放式的beta測試是沒用的。要是你那樣做,只可能有兩種結(jié)果。一種結(jié)果是你有太多的測試者(就像Netscape那樣),這些人向你反饋了大量的意見,你從中根本不可能得到有用的數(shù)據(jù)。另一種結(jié)果是,現(xiàn)有的測試者根本不向你反饋他們的使用情況,導(dǎo)致你無法得到足夠的數(shù)據(jù)。

            2. 要想找到那些能夠向你反饋意見的測試者,最好的方法是訴諸他們“言行一致”的心理。你需要讓他們自己承諾會向你發(fā)送反饋意見,或者更好的方法是,讓他們自己申請參加beta測試。一旦他們采取了某些主動行為,比如填寫一張申請表,在“我同意盡快發(fā)回反饋意見和軟件故障報告”的選項上打勾,許多人就會發(fā)送反饋意見,因為他們想要“言行一致”。

            3. 不要妄想一次完整的beta測試的所有步驟能夠在少于8-10周的時間內(nèi)完成。我曾經(jīng)試過,結(jié)果是除非老天幫忙,否則根本不可能做到。

            4. 不要妄想在測試中發(fā)布新的軟件版本的頻率能夠快于每兩周一次。我曾經(jīng)試過,結(jié)果是除非老天幫忙,否則根本不可能有效。

            5. 一次beta測試中計劃發(fā)布的軟件版本不要少于4個。我從來沒試過少于4個版本,因為太明顯了,那樣不可能達到測試目的。

            6. 如果在測試過程中你為軟件添加了一個功能,那么哪怕這個功能非常微小,整個8個星期的測試也要回到起點,從頭來過,而且你還需要再發(fā)布3個或4個新版本。我犯過的最大錯誤之一就是,在CityDesk 2.0的beta測試接近尾聲的時候,我向軟件中加入了一些保留空格的代碼,這產(chǎn)生了一些意想不到的副作用(如果我們可以這樣說),測試的時間不夠了,我本應(yīng)該將測試時間加長、進一步收集數(shù)據(jù)的。

            7. 即使你有一個申請參加beta測試的步驟,最后也只有五分之一的測試者會向你提交反饋意見。

            8. 我們制定了一條政策,所有向我們提交反饋意見的測試者都將免費獲贈一份正版軟件。不管你的反饋意見是正面的,還是負面的,只要你提交給我們,就能獲得贈品。但是,在測試結(jié)束的時候,那些不提交反饋意見的測試者什么也不會得到。

            9. 你需要的嚴肅測試者(即那些會把反饋意見寫成3頁紙發(fā)送給你的人)的最小數(shù)量大約是100人左右。如果你獨立開發(fā)軟件,那么這是你能夠處理的反饋意見的最大數(shù)量。如果你有一支測試管理團隊或?qū)iT的beta測試經(jīng)理,那么設(shè)法分別為每個處理反饋意見的人找到100個嚴肅測試者。

            10. 根據(jù)第7條,即使你有一個參加beta測試的申請步驟,最后也只有五分之一的測試者會真地使用你的產(chǎn)品并將反饋意見發(fā)送給你。那么,假定你有一個質(zhì)量控制部門,里面一共有3個測試管理人員,這就意味著你必須批準1500份參加beta測試的申請表,因為這樣才能產(chǎn)生300個嚴肅測試者。批準的數(shù)量少于這個數(shù)目的話,你就不會得到充分的反饋意見;批準的數(shù)量多于這個數(shù)目的話,你就會被許許多多重復(fù)的反饋意見淹沒。

            11. 大多數(shù)beta測試的參與者只是在第一次拿到這個程序的時候才會去試用一下,然后就喪失了興趣。此后每次你推出一個新的版本并發(fā)送給他們,他們也不會有興趣重新測試它。除非他們每天都在用這個程序,但是對于大多數(shù)人來說,這是不可能的。因此,你需要錯開不同版本的測試對象,將你的所有beta測試參與者分成四組,每次發(fā)布一個新版本的時候,就把一個新的組加入測試,這樣就能保證每個版本都有第一次使用這個程序的測試者。

            12. 不要混淆技術(shù)beta和市場beta。我上面談的這些都是針對技術(shù)beta,它的目標是發(fā)現(xiàn)軟件中的錯誤和得到及時的用戶反饋意見。市場beta則是軟件正式發(fā)布前的預(yù)覽版本,對象主要是新聞媒體、大客戶和那些寫入門教程的家伙(該教程必須在軟件上市的同一天問世)。對于市場beta,你的目的并不是得到反饋意見。(雖然無論你怎么做,那些寫書的家伙很可能都會滔滔不絕地告訴你一大堆意見。如果你置之不理,這些意見就會被復(fù)制粘貼進他們自己的書里。)

          posted @ 2011-12-26 11:46 順其自然EVO 閱讀(160) | 評論 (0)編輯 收藏

          數(shù)據(jù)庫加密領(lǐng)域的五個最差實踐

          數(shù)據(jù)庫加密領(lǐng)域的五個最差實踐

           薄弱的加密措施讓數(shù)據(jù)庫關(guān)鍵信息面臨更多風(fēng)險。數(shù)據(jù)庫加密對于關(guān)鍵數(shù)據(jù)的存儲安全性有著巨大的意義,但這種積極意義產(chǎn)生的前提是首先將加密工作做好。隨著數(shù)據(jù)庫加密部署情況的日益增多,部署效果自然也隨之變得良莠不齊。以下五類數(shù)據(jù)庫加密部署是專家組們公認的最差實踐方式。為了獲得最理想的安全效益,我們應(yīng)該盡量避免如下幾類操作失誤。

            1、將密鑰保存在錯誤的地方

            據(jù)安全專家稱,很多人習(xí)慣于將加密的數(shù)據(jù)和密鑰一起存放,這稱得上是數(shù)據(jù)庫加密工作中的原罪之一。

            “如果你在你的數(shù)據(jù)庫中加密敏感信息,那么千萬不要把加密密鑰或者認證證書同與之相關(guān)加密數(shù)據(jù)存儲在一起。”電氣行業(yè)首席安全工程師Luther Martin說道,“一旦發(fā)生這種情況,雖然感覺上加密信息是安全的,其實整套體系已經(jīng)失去了實際意義。”

            若想真正地保護好數(shù)據(jù),要將密鑰妥善地加以管理;應(yīng)把它與加密數(shù)據(jù)、敏感信息密鑰之類,各自區(qū)分并存放。

            2、密鑰未能集中管理

            由于很多企業(yè)自身的安保機制較為薄弱,因此隨意將密鑰保存在防范措施不足的地方也就比較常見。

            “關(guān)鍵問題在于在企業(yè)內(nèi)部,使用大量密鑰和數(shù)字簽證的情況廣泛存在”,Venafi的CEO Jeff Hudson說,“研究表明,企業(yè)中所管理的認證及密鑰系統(tǒng)少則上千、多則上萬的現(xiàn)象非常普遍。”

            很多廠商都銷售加密產(chǎn)品,卻沒有向客戶教授相應(yīng)的管理應(yīng)用知識,Hudson說。

            “加密技術(shù)只是解決方案的一半。IT部門必須掌握監(jiān)控密鑰并需要了解都誰有權(quán)使用密鑰。為了維護整個企業(yè)的利益,快速為密鑰部署妥善的保護機制可謂至關(guān)重要,”他說。“為了嚴格貫徹訪問控制,職責(zé)分離以及策略改善制度,大家需要對自動化監(jiān)控密鑰和證書管理工作加深理解。”

            理論上,為了了解本地密鑰在哪里以及保護這些密鑰的具體方案,企業(yè)應(yīng)當(dāng)盡可能地集中管理密鑰。

            3、依靠自創(chuàng)的方案

            IT人士最怕的就是客戶自己搞出一套自創(chuàng)系統(tǒng),借以節(jié)約成本。但他們的利己意識倒不一定是壞事,因為除非你的員工都是具有多年經(jīng)驗的密碼專家,否則輕易使用自制的加密方案或者密鑰管理系統(tǒng)簡直就是自掘墳?zāi)埂?/p>

            “失敗的自主開發(fā)數(shù)據(jù)庫加密密鑰管理方案的部署,會迫使那些主要經(jīng)營零售業(yè)的廠商轉(zhuǎn)型為專業(yè)型供應(yīng)商” Protegrity公司的CTO Ulf Mattsson說:“這看起來非常容易但實際上相當(dāng)危險。”

            4、缺乏備份資料加密機制

            如果你只對數(shù)據(jù)庫進行加密,而不對相關(guān)數(shù)據(jù)的備份加以同樣的保護,也會讓你的企業(yè)陷入風(fēng)險當(dāng)中。

            “在我們生活的時代里,磁帶落在后備廂里,筆記本丟了等等所有意外情況都不能成為我們的借口,” 403網(wǎng)絡(luò)安全CEO Alan Wlasuk說“為所有數(shù)據(jù)庫的備份資料進行加密是一件理所當(dāng)然的事。”

            “即使表面上看來毫無價值,也要以00加密格式備份所有數(shù)據(jù)庫內(nèi)容,”他說“數(shù)據(jù)備份最終會存儲在一個意想不到的地方,如果你知道他們是安全的,你也就可以高枕無憂了。”

            5、使用過時的加密算法

            在去年11月Gawker遭受的重創(chuàng)中,部分原因就是密碼信息慘遭泄露,這些密碼被幾十年未更新過的陳舊加密技術(shù)保護著。而這一情況并非特例。許多企業(yè)都需要對數(shù)據(jù)進行加密,但使用的卻是超級老舊的加密方式,這簡直像是在用紙做的盔甲來保護自己的身體。

            “多年前使用的中古加密技術(shù)系統(tǒng)早就扛不住了” Wlasuk說。企業(yè)不僅僅要留心加密數(shù)據(jù)庫,同樣要關(guān)注哪些加密技術(shù)已經(jīng)過時、并迫切需要新的加密算法補充進來。

          posted @ 2011-12-26 11:43 順其自然EVO 閱讀(179) | 評論 (0)編輯 收藏

          好用的清理數(shù)據(jù)庫腳本

          1、腳本說明

            此腳本用于清空數(shù)據(jù)庫數(shù)據(jù),只刪除相關(guān)表記錄,保留表結(jié)構(gòu)及存儲過程觸發(fā)器等主要架構(gòu)。

            設(shè)計思路:

            1)根據(jù)表添加時間逆向獲取所有用戶表信息

            2)使用游標循環(huán)刪除每張表內(nèi)數(shù)據(jù)

            3)使用delete進行刪除,即使有外鍵關(guān)系同樣可以刪除表記錄

            4)表存在自增主鍵則將其重置為0

            5)截斷日志,將數(shù)據(jù)庫表空間及日志文件縮減到最小

            2、使用說明

            1)建立刪除數(shù)據(jù)庫存儲過程SP_DaTaBaSeClear

          以下是代碼片段:
          If( object_id('SP_DaTaBaSeClear') is not null ) drop procedure SP_DaTaBaSeClear go SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE SP_DaTaBaSeClearASBegin Transaction declare @BtableName varchar(200) declare curDel cursor for select rtrim(name) from sysobjects where type = 'U' order by crdate desc open curDel declare @delSQL varchar(500) fetch next from curDel into @BtableName while( @@fetch_status = 0) begin set @delSQL = 'delete from ' + @BtableName print @delSQL exec( @delSQL ) if( ident_seed(@BtableName) is not null ) begin dbcc checkident( @BtableName, reseed, 0 ) print '種子成功置為1' end fetch next from curDel into @BtableName end close curDel deallocate curDel Commit GO

            2)執(zhí)行該存儲過程,執(zhí)行過程中查看執(zhí)行信息,如有紅色信息則先手動刪除紅色信息表記錄

            -- 執(zhí)行存儲過程刪除表數(shù)據(jù)

            EXEC SP_DaTaBaSeClear

            3)如仍然報出紅色信息則直接執(zhí)行以下語句進行刪除

          以下是代碼片段:
          declare @BtableName varchar(128) declare curDel cursor for select rtrim(name) from sysobjects where type = 'U' order by crdate desc open curDel declare @delSQL varchar(255) fetch next from curDel into @BtableName while( @@fetch_status = 0) begin set @delSQL = 'delete from ' + @BtableName print @delSQL exec( @delSQL ) if( ident_seed(@BtableName) is not null ) begin dbcc checkident( @BtableName, reseed, 0 ) print '種子成功置為1' end fetch next from curDel into @BtableName end close curDel deallocate curDel

            4)最后執(zhí)行腳本重置數(shù)據(jù)庫大小

          以下是代碼片段:
              backup log @DataBaseName with no_log dbccshrinkdatabase(@DataBaseName)
            dbccupdateusage(@DataBaseName)

          posted @ 2011-12-26 11:40 順其自然EVO 閱讀(243) | 評論 (0)編輯 收藏

          解讀Java環(huán)境變量配置

          1、查看當(dāng)前可用的所有環(huán)境變量(=系統(tǒng)變量+用戶變量)

            set

            查看某個環(huán)境變量,如PATH

            set PATH

            添加環(huán)境變量,如xxx=aa

            set xxx=aa

            將環(huán)境變量(如xxx)的值置為空

            set xxx=

            在某個環(huán)境變量(如PATH)后添加新的值(如d:\xxx)

            set PATH=%PATH%;d:\xxx

            [注]:以命令行方式對環(huán)境變量的操作只對當(dāng)前窗口的應(yīng)用有效!

            2、WindowsJAVA用到的環(huán)境變量主要有3個:JAVA_HOME、CLASSPATH、PATH。

            1)JAVA_HOME指向的是JDK的安裝路徑,如x:\ j2sdk1.4.2,在這路徑下你應(yīng)該能夠找到bin、lib等目錄。設(shè)置方法:JAVA_HOME=c:\ j2sdk1.4.2

            2)PATH變量的作用

            java程序在運行時首先在path變量所定義的路徑去找java.exe,并以最先找到的為準,如果安裝完j2sdk后不加設(shè)置,一般是C:\WINDOWS\system32目錄。

            j2sdk1.4(還有其它java開發(fā)工具如jbuilder8)在安裝后會將java.exe拷貝到C:\WINDOWS\system32目錄下,當(dāng)執(zhí)行java.exe時,需要裝載這個SDK下的一些文件。

            如j2sdk1.4在安裝完成后,C:\WINDOWS\system32下的java.exe在運行時會在C:\Program File\java\目錄下裝載必需的一些文件。但安裝j2sdk后一般會在PATH變量的最前面設(shè)置C:\ j2sdk1.4.2 \bin。

            當(dāng)先安裝j2sdk1.4.2,后安裝jbuilder8等開發(fā)工具時,由于jbuilder8的java.exe在拷貝到C:\WINDOWS\system32時可能覆蓋了j2sdk1.4.2的java.exe,那么這時在運行的java.exe會到j(luò)builder8所在的目錄去裝載必需的一些文件。

            3)CLASSPATH環(huán)境變量的作用

            告訴類裝載器到哪里去尋找第三方提供的類和用戶定義的類。也可用使用JVM命令行參數(shù)-classpath分別為應(yīng)用程序指定類路徑,在-classpath中指定的類路徑覆蓋CLASSPATH環(huán)境變量中指定的值。

            3、當(dāng)機器內(nèi)裝有多個SDK版本時,如何查看所用的是哪個SDK?

            java -verbose

            在出現(xiàn)的屏幕信息中可以看出系統(tǒng)裝載的是哪個目錄下的文件。

            4、Windows OS下設(shè)置PATH的方法

            〔系統(tǒng)〕->〔環(huán)境〕-> 〔高級〕,在PATH變量的文本框中的最前面輸入C:\ j2sdk1.4.2\bin

            或在命令行窗口中執(zhí)行 set path=c:\j2sdk1.4.2\bin;%path%; 這樣在命令行窗口的任一路徑下都可以執(zhí)行java.exe程序了。或設(shè)置PATH=%JAVA_HOME%\bin;%PATH%

            5、對于CLASSPATH環(huán)境變量的設(shè)置方法要加倍小心,是因為以后你出現(xiàn)的莫名其妙80%以上的怪問題都可能是由于CLASSPATH設(shè)置不對引起的

            CLASSPATH=.\;%JAVA_HOME%\lib\tools.jar

            首先要注意的是最前面的".\;",——句點反斜杠分號。這個是告訴JDK,搜索CLASS時先查找當(dāng)前目錄的CLASS文件。

            【Troubleshooting】

            編譯會出現(xiàn)以下情況,看你是否真得都理解環(huán)境變量的設(shè)置,并能解決它。

            [T1] error:java不是一個可運行的程序? 由于沒有設(shè)置環(huán)境變量path

            [T2] error:不能打開某個目錄? 可能是忽視了path環(huán)境變量中的目錄的設(shè)置順序。

            [T3] Exception on thread “main” java.lang.DoClassDefFoundError:Test?沒有設(shè)置classpath的路徑。

          posted @ 2011-12-26 11:39 順其自然EVO 閱讀(261) | 評論 (0)編輯 收藏

          僅列出標題
          共394頁: First 上一頁 345 346 347 348 349 350 351 352 353 下一頁 Last 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 平顺县| 石棉县| 图木舒克市| 红桥区| 佛教| 成武县| 法库县| 阳谷县| 原平市| 衡山县| 应城市| 玉门市| 中西区| 综艺| 贵南县| 开江县| 平利县| 六盘水市| 武穴市| 桦甸市| 岳普湖县| 彝良县| 宜春市| 霍林郭勒市| 突泉县| 沾益县| 盖州市| 晴隆县| 扎兰屯市| 威海市| 大理市| 克东县| 自治县| 泉州市| 庆阳市| 鄂温| 阿尔山市| 盐城市| 齐齐哈尔市| 贵南县| 周至县|