1. 程式人生 > >一個C#開發者重溫Java的心路歷程

一個C#開發者重溫Java的心路歷程

前言

我們都知道軟體開發是工科,不是理科;本質上和電工、鉗工是一樣的。

也就是說,軟體技術成長也與電工、鉗工的技術成長是一樣的,靠的是練,而不是學。

所以,很多時候,我們稱應屆大學生是一張白紙,啥也不會。

不論他在學校學的多好,都沒用,因為他沒練過,不能幹活;同理,不論他在學校學的多差,進入工作崗位後,只要肯練,工作也不成問題。

即,剛畢業的學生,只要你做的是工科的軟體開發,不是科學類的理科研發;那麼,本質上,大家是不存在優秀與普通的差別的。

為什麼要學習Java?

在Web端,Java是毫無疑問的領頭羊;所以,從事Web開發的Net開發者學習一下Java,其實還是很有益處的,取長補短嘛。 

而且,在工作中我們難免是要遇到和Java介面對接的情況的;如果你足夠了解Java,那麼,對方是否假配合你很快就能發覺了;如果被人搞到離職了,還跟人稱兄道弟的,就有點Low了。

下面,我以IDEA(Java的VisualStudio),建立一個Spring專案,重溫一下Java。

Java重溫

首先開啟IDEA,點選File-New-Project(我手上只有英文版IDEA);如下圖:

 

在NewProject介面裡,選擇Spring Intinalizr,然後勾選Default,點選Next;

然後我們會經歷一個【等待介面】,該介面是用來下載Spring模板的;這是因為Spring的模板不在IDEA中整合,所以建立時,需要在網上下載。

由於VisualStudio集成了大量模板,所以,我們幾乎不用自己去找模板下載;如果情況特殊,我們需要找模板的話,那也是到網站上下載,然後手動安裝。比如MVC2的時代,你想用MVC3的模板。

所以,對於Net開發而言,這種IDE提供下載模板渠道的模式,我們還是比較陌生的。不過IDEA也提供手動安裝模板的功能,勾選Custom就可以使用手動安裝模式了。

【等待介面】結束後,進入下圖介面:

 

這個介面裡有兩個引數需要設定,一個是Group,一個是Artifact。那麼這兩個引數的作用是什麼呢?

從字面上我是理解不了的,於是我百度了一下。。。然後,呃。。。我還是很混亂。。。

調查後,我大概得出一個結果,就是Group和Artifact是這個專案的唯一標識,Group是組織唯一標識,Artifact是專案唯一標識。

呃。。。我想,對於對於Net開發而言,這應該是很難理解的。專案唯一標識?這是什麼鬼?唯一標識這個詞怎麼聽起來像主鍵呢。。。專案怎麼還需要唯一標識呢。。。

那到底要如何解釋他們呢?

我想,應該是這樣的,Java建立者的初始目的可能是想建立一個地球村共榮圈。。。所以,每一個Java專案都被期待著被共享,如果專案被共享,那麼專案就需要唯一標識Artifact。如果一個公司共享了多個專案,那要證明這些專案都從屬於該公司,那就需要組織(公司)唯一標識Group。

換成Net的描述就是,你建立的每一個Net專案都被微軟期待著,共享到Nuget上,所以你建立專案之前,要先建立這個專案在Nuget上的唯一標識。(很顯然微軟沒有這個期待)

這樣,似乎就很好理解Group和Artifact了。

但是,因為現實中,不論Java還是Net都不可能每個專案都共享,所以,當我們做一個非開源專案時,這兩個屬性設定,就有點雞肋了。

----------------------------------------------------------------------------------------------------

下面看一下,我認為這個介面中第三個重要的屬性配置—Package。

可以在圖中看到,系統預設把Package賦值成了Group+Artifact的值了—kibagroup.kibaarifact。

這裡的Package大約等於C#裡的名稱空間。呃。。。然後,這個預設賦值我就覺得很奇葩了。。。

比如,你做了唯一標識,Group等於公司名kibacompany,Artifact等於專案kibatest;然後,你專案的預設名稱空間就是kibacompany.kibatest。。。

很顯然,這件事,對我而言很難理解,還好,IDEA支援我們去修改預設Package。

----------------------------------------------------------------------------------------------------

這裡我們修改Package為KibaJavaStart。

修改完Package後,我們點選Next繼續,如下圖:

 

 選擇圖中的Web專案和其子選項中的Spring Web,然後點選下一步。

 

如上圖所示,我們建立專案已經到了最後一步了,因為右下角不在是Next,而是Finish了。

在最後的這個介面裡,系統提示我們設定ProjectName(專案名稱)。

根據Net的習慣,專案名稱通常和預設名稱空間一樣,所以這裡我也賦值KibaJavaStart。

點選Finish,專案建立完成,介面如下:

專案簡介

在上圖中有三個大資料夾,和若干檔案。

資料夾

其中前兩個.idea和.mvn分別是IDEA開發工具和Maven管理工具的配置檔案、管理檔案等等(Maven類似nuget,但它還管理程式碼的生成和釋出。。。貌似比IEDA還好用。。。這裡Net開發就需要轉變一下觀念了,因為Java不是C#一家獨大,所以他的相關工具存在的功能重複的問題,所以Java開發通常都是用組合工具在開發,不像我們一個VisualStudio走天下)

第三個src是我們專案的核心檔案,java程式碼都在這裡;src我猜就是source的意思,不知道為什麼它不用全拼。。。

我們可以看到,在展開的src資料夾中,有著一層,兩層,三層。。。呃。。。好多層資料夾。。。誰說的臃腫。。。

呃。。。我們可以看到其中java這個資料夾的顏色是不一樣的,它代表的著,它下面的程式碼是核心Java程式碼。

與java資料夾同級的resources資料夾,顧名思義,存的是資原始檔;不過他這個資原始檔幾乎什麼都可以儲存,比如圖片,配置字串,XML資料,SQL查詢語句等等。(可能Net專案很少如此集中的儲存資源,所以感官上可能會有些奇怪,但我覺得java的這種資源集中的做法是很科學的,非常值得Net開發借鑑學習)

----------------------------------------------------------------------------------------------------

檔案

在剩下的若干檔案中,我們暫時只關注Pom.xml檔案;它是Java的配置檔案,不過他並不類似於Net的App.config,他相對的更接近Net的.csproj工程檔案,裡面儲存引用了那些Jar包(Net裡就是dll)。

Java的Web是有類似於Net的App.config檔案的檔案的,他叫做web.xml,不過,很明顯,我們在這裡看不到,我們暫時不關注他,後文會講到它。

Java裡還有個資料配置檔案,在這裡配置的資訊可以在Java程式碼裡被訪問;他就是java的資料配置檔案在resources資料夾下的application.properties(類似App.config的AppSettings使用configSource把配置檔案外放)如下圖:

Web專案開發

首先,我們找到我們的預設名稱空間,Java裡的預設包—KibaJavaStart,如下圖:

可以看到,在KibaJavaStart包下只有一個類ArtifactApplication,類裡只有一個方法Main。

Main方法?不是Web專案嗎?怎麼還有Main方法?

如果你這麼想,那一定是你Low了,嘿嘿;學一下Asp.Net Core吧,我們的Core也有Main函數了。

Asp.Net Core學習導航

學習了Asp.Net Core我們就瞭解了,這個承載Main函式的Application類,就是Asp.Net Core的Program類。

吐槽一下

1,現在專案建立完成後,系統在生成一個Main函式啟動類時,使用了Arifact的值來做開頭;這事很奇怪,Arifact是和Group在第一步一起建立的,兩者是上下級關係;但現在Arifact又突然的和最後一步建立預設包名成了上下級關係,這感覺太詭異了,為什麼不直接用Application命名呢,非要這樣結合一下呢?

2,專案建立完成後自帶的專案檔案也太少了吧,就一個Main函式啟動類,這讓人怎麼自學啊,逼著我們去看教程啊。

----------------------------------------------------------------------------------------------------

言歸正傳,一起看程式碼。。。

首先第一行程式碼,宣告包名稱。

package KibaJavaStart;

意義很簡單,就是宣告類所在的包名;不過,這裡與C#不同的是,這個包名是固定的,不可修改的。

也就是說,這個類檔案在資料夾KibaJavaStart下,他的包名就必須是KibaJavaStart;如果是在資料夾KibaJavaStart/Test下,他的包名就必須是KibaJavaStart.Test。

是的,這的確很不方便,不過,我們換一個角度考慮,Java資料夾的設定已經很臃腫了,剛剛建立就來了好幾層,如果不強制包名稱和資料夾名一致,那隻怕會帶來更多的不便。

我們接著看程式碼。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

宣告包名後,引入兩個Spring包,理由很簡單,因為Main函式要使用這兩個包裡的內容。

這裡import與C#裡的Using引用名稱空間的用法類似。

因為建立的是Spring專案,所以一些相關的Spring的Jar依賴(類似C#的Dll)已經被預設引用進來了,可以在專案的External Libraries下找到相關引用;如下圖:

我們知道在C#專案中,被引用的DLL會被複制一份到本地目錄。

不過,在Java專案卻不是這樣的,我們開啟專案的所在檔案目錄,會發現,目錄裡並沒有這些Jar檔案。

所以我猜想,被引用的Jar還在原來的位置,只有被編譯的時候才會被呼叫。

----------------------------------------------------------------------------------------------------

在Java裡,JDK自帶的Jar包相對比Net而言,還是較少的,所以,在開發Java時,通常要引用很多很多個Jar包。

比如Spring框架就不在JDK自帶的Jar包裡,所以,使用Spring框架開發專案,就要先下載其相應的Jar包。

因為,我們是使用IDEA開發工具開發,而IDEA預設的下載Jar包的工具是Maven,那麼下載的Jar包自然是由Maven管理;即,它們應該在Maven工具的所在目錄下。

Maven管理工具好像是沒有介面的,只能用命令列來操作;不過IDEA為我們提供了操作Maven的介面,現在我們開啟IDEA提供的Maven操作介面。

File—Settings—Build,Execution,Deployment—BuildTools—Maven,如下圖:

可以看到Maven不僅支援下載Jar包,還支援自定義儲存下載Jar包的位置。

圖中的Local repository就是儲存已下載Jar包的位置了。

----------------------------------------------------------------------------------------------------

回到程式碼。

@SpringBootApplication

這種@開頭的東西叫註解,它使用方式與C#的特性類似,要放在類,函式,屬性上面;然後在註解(特性)的定義裡去找到它的宿主(類or函式or屬性),然後為他增加特性;當然,也可設定成只支援類或者只支援函式的模式。

不過Java裡的註解實在是太多了、太強大了、太複雜了;註解不僅擁有各種各樣的功能,還互相依賴,甚至註解和註解之間還有巢狀;目前Java已經發展到了不使用註解,開發就舉步維艱的地步了。

有些註解在Net開發看來,真的有些奇葩,比如這個@Data註解,你都想象不到他是幹什麼的。 

如上圖所示,我們定義了一個實體類DataTest ;類裡定義兩個私有欄位,然後我們在類的頭上加了一個Data註解,然後。。。然後。。。

然後,這個Data註解就會自動給這兩個私有欄位變成屬性。。。

也許是因為我定義實體時總是想著他要被充血,所以我才覺得這注解很奇葩吧。。。

在上圖中我們還可以看到,@Data註解是紅色的,這是因為,我們還沒有引入他依賴的Jar包。如何引用呢?呃。。。目前我只知道一種方法。。。

開啟pom.xml,找到dependencies標籤,在他的下面新增@Data依賴的Jar包 (手敲的),如下圖:

圖中除了@Data的依賴的lombok包,還有兩個依賴,一個是spring-boot-starter,一個是spring-boot-starter-web;簡單介紹下,這兩個依賴是Spring框架的基礎依賴,如果建立專案時未幫我們自動新增這倆依賴,則需要我們手動新增一下,不然會影響專案執行。

PS:在dependency標籤中,我們會發現,他的子標籤是groupId和artifactId,而spring-boot-starter包和spring-boot-starter-web包的groupId又是一樣的,結合我們上文建立專案時設定Group和Artifact,可以想到,spring-boot-starter包和spring-boot-starter-web包都是由org.springframework.boot組織建立的開源專案,而我們在專案中,引用這種開源專案時,需要在dependency標籤下增加groupId和artifactId兩個標籤,並在其中填寫這個專案建立時設定的Group和Artifact屬性值。

----------------------------------------------------------------------------------------------------

在Java的工程檔案裡新增完依賴後,我們所依賴的Jar並不會被下載,還需要手動使用Maven來下載,(這個下載依賴庫的方式有點倒序的意思和Net不一樣)順序如下。

1,點選左下角快捷圖示,開啟Maven管理工具,如下圖:

點選後,右側會彈出Maven管理工具,如下圖:

點選圖中紅框內的下載按鈕,然後彈出浮動窗,在浮動窗內點選第一項Download Source,如下圖:

 

然後IDEA下方會出現一個下載進度條,雙擊進度條可以最大化,裡面有詳細資訊(如果網速很快或者Jar包很小,該進度條可能一閃而過),如下圖:

 

最後我們回到實體類,將滑鼠放到@Data上,點選Alt+Enter,然後在彈出的浮動窗上點選Import class,然後系統會為我們引入@Data註解所屬的Jar包—import lombok.Data;。

現在@Data註解就可以正常運行了,不過,這個過程好像有點。。。

----------------------------------------------------------------------------------------------------

回到註解@SpringBootApplication。。。

註解@SpringBootApplication是一個組合註解,包含@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。

@SpringBootConfiguration:將當前類標記為配置類。上文我提到了Java專案裡有個web.xml配置檔案(類似app.config),不過建立專案時並沒有自動生成;其原因就是這個註解了。

Spring框架專案編譯時會檢測這個註解(組合註解@SpringBootApplication也會被檢測),檢測到後會把這個類下的函式,全部提取出來,然後在逐個處理; 怎麼處理呢?我猜,是通過反射找到函式的函式名,引數,然後執行一下得到返回值;然後把這些字串組成複合規則的Xml標籤,再寫進web.xml配置檔案。

這樣做的好處就是繁瑣的XML檔案配置,被轉化成了程式碼編寫,而且java專案的web.xml最終好像是會被編譯進jar,所以這種動態生成web.xml的模式好想也沒什麼問題。

@EnableAutoConfiguration,@ComponentScan簡單理解就是使其他註解生效,如@Controller等;換言之,是使其他註解狀態為Enable和為其他註解提供配置資訊的註解。

即該註解是其他註解的依賴。。。。。。

----------------------------------------------------------------------------------------------------

我們接著看程式碼,現在到了類的主體程式碼了,程式碼如下:

public class ArtifactApplication {

	public static void main(String[] args) {
		SpringApplication.run(ArtifactApplication.class, args);
	} 
}

可以看到,該類是一個擁有Main函式的入口類,類裡Main函式主要實現一個功能呼叫SpringApplication名稱空間下的靜態方法Run。

我猜測,該方法的主要功能和AspNetCore的 WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build();這句話是一個意思,都是啟動一個伺服器程序。

服務程序啟動以後,就可以把我們的Web搭建進去了,我們可以看到Run函式第一個引數就要求主類的類名,這代表伺服器啟動後,會通過這個入參來啟動Web專案。

這裡Srping和Core的區別就是Spring啟動的伺服器是Tomcat,而Core啟動的伺服器是Kestrel。

建立一個Api

現在Java專案我們已經建立完了,該瞭解的基礎我們也瞭解了,那麼讓我們一起建立一個Api,然後執行一下看看效果吧。

首先我們建立一個ApiController的資料夾,然後新增一個HelloController檔案,然後編寫程式碼如下:

@RestController
public class HelloController
{
    @RequestMapping(value = "/GetName", method = RequestMethod.GET)
    public String GetName()
    {
        return "我是Kiba518";
    }
    @RequestMapping(value = "/GetAge", method = RequestMethod.GET)
    public int GetAge()
    {
        return 518;
    }
}

可以看到,程式碼中在類的上面加了一個註解@RestController,該註解表示當前類是一個遵循REST風格的Api類;類似於Net裡的Controller繼承ApiController。

接著我們建立了兩個函式GetName和GetAge;他們的頭上使用@RequestMapping註解,該註解的作用是設定訪問該函式的地址。

即,函式GetName和GetAge的訪問地址為 http://127.0.0.1:8010/GetName和 http://127.0.0.1:8010/GetAge;訪問時,我們需要注意,GetName和GetAge這個地址是區分大小寫的。。。

現在Shift+F10執行下專案,測試一下我們的WebApi。

 如上圖,WebApi訪問成功。不過我們訪問的埠是8010。

還記得上面說的Spring啟動時會建立一個伺服器嗎,這個埠就是伺服器監聽的埠。

當然了,這個埠是可配置的,配置的位置就在application.properties裡。

不過.properties檔案編寫和閱讀不太方便,我們把他改為.yml,然後修改程式碼如下:

server:
    port: 8010

這個配置檔案裡的內容是可以被Java訪問的,而且Spring框架專案編譯時也會先讀這裡的內容,找到同名的配置,就會替換預設的配置。

PS:Java中控制訪問地址的註解非常多,控制地址訪問的模式也非常多,多到有點誇張的地步。。。

結語

從開發工具的角度來看,Java的開發工具的使用相較Net而言,是比較怪異的,因為,它有一些工具的設計和使用是倒序的。

而Java工具又比較多,因此,這種正序工具和倒序工具同時存在同時使用,感覺上就有一點怪,不過習慣了以後倒也沒什麼。

從開發的角度來看,Java的主流Spring和Net幾乎沒有什麼區別,唯一的區別就是Java使用註解而Net使用繼承。

----------------------------------------------------------------------------------------------------

程式碼已經傳到Github上了,歡迎大家下載。

Github地址:https://github.com/kiba518/KibaJavaStart

----------------------------------------------------------------------------------------------------

注:此文章為原創,任何形式的轉載都請聯絡作者獲得授權並註明出處!
若您覺得這篇文章還不錯,請點選下方的【推薦】,非常感謝!

https://www.cnblogs.com/kiba/p/12052925.html