- verview
- Connector Init and Start
- Request Process
- Acceptor
- Poller
- Worker
- Container
- Reference
建議結合《談談 Tomcat 架構及啟動過程[含部署]》一起看!
談談 Tomcat 架構及啟動過程[含部署]
http://www.importnew.com/27724.html
很多東西在時序圖中體現的已經非常清楚了,沒有必要再一步一步的作介紹,所以本文以圖為主,然后對部分內容加以簡單解釋。
繪制圖形使用的工具是 PlantUML + Visual Studio Code + PlantUML Extension
本文對 Tomcat 的介紹以 Tomcat-9.0.0.M22 為標準。
Tomcat-9.0.0.M22 是 Tomcat 目前最新的版本,但尚未發布,它實現了 Servlet4.0 及 JSP2.3 并提供了很多新特性,需要 1.8 及以上的 JDK 支持等等,詳情請查閱 Tomcat-9.0-doc。
https://tomcat.apache.org/tomcat-9.0-doc/index.html
Overview
Connector 啟動以后會啟動一組線程用于不同階段的請求處理過程。
- Acceptor 線程組。用于接受新連接,并將新連接封裝一下,選擇一個 Poller 將新連接添加到 Poller 的事件隊列中。
- Poller 線程組。用于監聽 Socket 事件,當 Socket 可讀或可寫等等時,將 Socket 封裝一下添加到 worker 線程池的任務隊列中。
- worker 線程組。用于對請求進行處理,包括分析請求報文并創建 Request 對象,調用容器的 pipeline 進行處理。
Acceptor、Poller、worker 所在的 ThreadPoolExecutor 都維護在 NioEndpoint 中。
Connector Init and Start
- initServerSocket(),通過 ServerSocketChannel.open() 打開一個 ServerSocket,默認綁定到 8080 端口,默認的連接等待隊列長度是 100, 當超過 100 個時會拒絕服務。我們可以通過配置 conf/server.xml 中 Connector 的 acceptCount 屬性對其進行定制。
- createExecutor() 用于創建 Worker 線程池。默認會啟動 10 個 Worker 線程,Tomcat 處理請求過程中,Woker 最多不超過 200 個。我們可以通過配置 conf/server.xml 中 Connector 的 minSpareThreads 和 maxThreads 對這兩個屬性進行定制。
- Pollor 用于檢測已就緒的 Socket。默認最多不超過 2 個,Math.min(2,Runtime.getRuntime().availableProcessors());。我們可以通過配置 pollerThreadCount 來定制。
- Acceptor 用于接受新連接。默認是 1 個。我們可以通過配置 acceptorThreadCount 對其進行定制。
Request Process
Acceptor
- Acceptor 在啟動后會阻塞在 ServerSocketChannel.accept(); 方法處,當有新連接到達時,該方法返回一個 SocketChannel。
- 配置完 Socket 以后將 Socket 封裝到 NioChannel 中,并注冊到 Poller,值的一提的是,我們一開始就啟動了多個 Poller 線程,注冊的時候,連接是公平的分配到每個 Poller 的。NioEndpoint 維護了一個 Poller 數組,當一個連接分配給 pollers[index] 時,下一個連接就會分配給 pollers[(index+1)%pollers.length].
- addEvent() 方法會將 Socket 添加到該 Poller 的 PollerEvent 隊列中。到此 Acceptor 的任務就完成了。
Poller
- selector.select(1000)。當 Poller 啟動后因為 selector 中并沒有已注冊的 Channel,所以當執行到該方法時只能阻塞。所有的 Poller 共用一個 Selector,其實現類是 sun.nio.ch.EPollSelectorImpl
- events() 方法會將通過 addEvent() 方法添加到事件隊列中的 Socket 注冊到 EPollSelectorImpl,當 Socket 可讀時,Poller 才對其進行處理
- createSocketProcessor() 方法將 Socket 封裝到 SocketProcessor 中,SocketProcessor 實現了 Runnable 接口。worker 線程通過調用其 run() 方法來對 Socket 進行處理。
- execute(SocketProcessor) 方法將 SocketProcessor 提交到線程池,放入線程池的 workQueue 中。workQueue 是 BlockingQueue 的實例。到此 Poller 的任務就完成了。
Worker
- worker 線程被創建以后就執行 ThreadPoolExecutor 的 runWorker() 方法,試圖從 workQueue 中取待處理任務,但是一開始 workQueue 是空的,所以 worker 線程會阻塞在 workQueue.take() 方法。
- 當新任務添加到 workQueue后,workQueue.take() 方法會返回一個 Runnable,通常是 SocketProcessor,然后 worker 線程調用 SocketProcessor 的 run() 方法對 Socket 進行處理。
- createProcessor() 會創建一個 Http11Processor, 它用來解析 Socket,將 Socket 中的內容封裝到 Request 中。注意這個 Request 是臨時使用的一個類,它的全類名是 org.apache.coyote.Request,
- postParseRequest() 方法封裝一下 Request,并處理一下映射關系(從 URL 映射到相應的 Host、Context、Wrapper)。
- CoyoteAdapter 將 Rquest 提交給 Container 處理之前,并將 org.apache.coyote.Request 封裝到 org.apache.catalina.connector.Request,傳遞給 Container 處理的 Request 是 org.apache.catalina.connector.Request。
- connector.getService().getMapper().map(),用來在 Mapper 中查詢 URL 的映射關系。映射關系會保留到 org.apache.catalina.connector.Request 中,Container 處理階段 request.getHost() 是使用的就是這個階段查詢到的映射主機,以此類推 request.getContext()、request.getWrapper() 都是。
- connector.getService().getContainer().getPipeline().getFirst().invoke() 會將請求傳遞到 Container 處理,當然了 Container 處理也是在 Worker 線程中執行的,但是這是一個相對獨立的模塊,所以單獨分出來一節。
Container
- 需要注意的是,基本上每一個容器的 StandardPipeline 上都會有多個已注冊的 Valve,我們只關注每個容器的 Basic Valve。其他 Valve 都是在 Basic Valve 前執行。
- request.getHost().getPipeline().getFirst().invoke() 先獲取對應的 StandardHost,并執行其 pipeline。
- request.getContext().getPipeline().getFirst().invoke() 先獲取對應的 StandardContext,并執行其 pipeline。
- request.getWrapper().getPipeline().getFirst().invoke() 先獲取對應的 StandardWrapper,并執行其 pipeline。
- 最值得說的就是 StandardWrapper 的 Basic Valve,StandardWrapperValve
- allocate() 用來加載并初始化 Servlet,值的一提的是 Servlet 并不都是單例的,當 Servlet 實現了 SingleThreadModel 接口后,StandardWrapper 會維護一組 Servlet 實例,這是享元模式。當然了 SingleThreadModel在 Servlet 2.4 以后就棄用了。
- createFilterChain() 方法會從 StandardContext 中獲取到所有的過濾器,然后將匹配 Request URL 的所有過濾器挑選出來添加到 filterChain 中。
- doFilter() 執行過濾鏈,當所有的過濾器都執行完畢后調用 Servlet 的 service() 方法。
Reference
- 《How Tomcat works》
- https://www.amazon.com/How-Tomcat-Works-Budi-Kurniawan/dp/097521280X
- 《Tomcat 架構解析》– 劉光瑞
- http://product.dangdang.com/25084132.html
- Tomcat-9.0-doc
- https://tomcat.apache.org/tomcat-9.0-doc/index.html
- apache-tomcat-9.0.0.M22-src
- http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.0.M22/src/
- tomcat架構分析 (connector NIO 實現)
- http://gearever.iteye.com/blog/1844203
來源:http://rrd.me/ehmDB
:-D 搜索微信號(ID:芋道源碼),可以獲得各種 Java 源碼解析、原理講解、面試題、學習指南。
:-D 并且,回復【書籍】后,可以領取筆者推薦的各種 Java 從入門到架構的 100 本書籍。
:-D 并且,回復【技術群】后,可以加入專門討論 Java、后端、架構的技術群。
源:Rainstorm ,github.com/c-rainstorm/blog/blob/master/tomcat/談談%20Tomcat%20架構及啟動過程%5B含部署%5D.md
這個題目命的其實是很大的,寫的時候還是很忐忑的,但我盡可能把這個過程描述清楚。因為這是讀過源碼以后寫的總結,在寫的過程中可能會忽略一些前提條件,如果有哪些比較突兀就出現,或不好理解的地方可以給我提 Issue,我會盡快補充修訂相關內容。
很多東西在時序圖中體現的已經非常清楚了,沒有必要再一步一步的作介紹,所以本文以圖為主,然后對部分內容加以簡單解釋。
繪制圖形使用的工具是 PlantUML + Visual Studio Code + PlantUML Extension
圖形 PlantUML 源文件:
- tomcat-architecture.pu
- tomcat-init.pu
- tomcat-start.pu
- tomcat-context-start.pu
- tomcat-background-thread.pu
本文對 Tomcat 的介紹以 Tomcat-9.0.0.M22 為標準。
Tomcat-9.0.0.M22 是 Tomcat 目前最新的版本,但尚未發布,它實現了 Servlet4.0 及 JSP2.3 并提供了很多新特性,需要 1.8 及以上的 JDK 支持等等,詳情請查閱 Tomcat-9.0-doc
Tomcat-9.0-dochttps://tomcat.apache.org/tomcat-9.0-doc/index.html
Overview
- Bootstrap 作為 Tomcat 對外界的啟動類,在 $CATALINA_BASE/bin 目錄下,它通過反射創建 Catalina 的實例并對其進行初始化及啟動。
- Catalina 解析 $CATALINA_BASE/conf/server.xml 文件并創建 StandardServer、StandardService、StandardEngine、StandardHost 等
- StandardServer 代表的是整個 Servlet 容器,他包含一個或多個 StandardService
- StandardService 包含一個或多個 Connector,和一個 Engine,Connector 和 Engine 都是在解析 conf/server.xml 文件時創建的,Engine 在 Tomcat 的標準實現是 StandardEngine
- MapperListener 實現了 LifecycleListener 和 ContainerListener 接口用于監聽容器事件和生命周期事件。該監聽器實例監聽所有的容器,包括 StandardEngine、StandardHost、StandardContext、StandardWrapper,當容器有變動時,注冊容器到 Mapper。
- Mapper 維護了 URL 到容器的映射關系。當請求到來時會根據 Mapper 中的映射信息決定將請求映射到哪一個 Host、Context、Wrapper。
- Http11NioProtocol 用于處理 HTTP/1.1 的請求
- NioEndpoint 是連接的端點,在請求處理流程中該類是核心類,會重點介紹。
- CoyoteAdapter 用于將請求從 Connctor 交給 Container 處理。使 Connctor 和 Container 解耦。
- StandardEngine 代表的是 Servlet 引擎,用于處理 Connector 接受的 Request。包含一個或多個 Host(虛擬主機), Host 的標準實現是 StandardHost。
- StandardHost 代表的是虛擬主機,用于部署該虛擬主機上的應用程序。通常包含多個 Context (Context 在 Tomcat 中代表應用程序)。Context 在 Tomcat 中的標準實現是 StandardContext。
- StandardContext 代表一個獨立的應用程序,通常包含多個 Wrapper,一個 Wrapper 容器封裝了一個 Servlet,Wrapper的標準實現是 StandardWrapper。
- StandardPipeline 組件代表一個流水線,與 Valve(閥)結合,用于處理請求。 StandardPipeline 中含有多個 Valve, 當需要處理請求時,會逐一調用 Valve 的 invoke 方法對 Request 和 Response 進行處理。特別的,其中有一個特殊的 Valve 叫 basicValve,每一個標準容器都有一個指定的 BasicValve,他們做的是最核心的工作。
- StandardEngine 的是 StandardEngineValve,他用來將 Request 映射到指定的 Host;
- StandardHost 的是 StandardHostValve, 他用來將 Request 映射到指定的 Context;
- StandardContext 的是 StandardContextValve,它用來將 Request 映射到指定的 Wrapper;
- StandardWrapper 的是 StandardWrapperValve,他用來加載 Rquest 所指定的 Servlet,并調用 Servlet 的 Service 方法。
Tomcat init
- 當通過 ./startup.sh 腳本或直接通過 java 命令來啟動 Bootstrap 時,Tomcat 的啟動過程就正式開始了,啟動的入口點就是 Bootstrap 類的 main 方法。
- 啟動的過程分為兩步,分別是 init 和 start,本節主要介紹 init;
- 初始化類加載器。[關于 Tomcat 類加載機制,可以參考我之前寫的一片文章:談談Java類加載機制]
- 通過從 CatalinaProperties 類中獲取 common.loader 等屬性,獲得類加載器的掃描倉庫。CatalinaProperties 類在的靜態塊中調用了 loadProperties() 方法,從 conf/catalina.properties 文件中加載了屬性.(即在類創建的時候屬性就已經加載好了)。
- 通過 ClassLoaderFactory 創建 URLClassLoader 的實例
- 通過反射創建 Catalina 的實例并設置 parentClassLoader
- setAwait(true)。設置 Catalina 的 await 屬性為 true。在 Start 階段尾部,若該屬性為 true,Tomcat 會在 main 線程中監聽 SHUTDOWN 命令,默認端口是 8005.當收到該命令后執行 Catalina 的 stop() 方法關閉 Tomcat 服務器。
- createStartDigester()。Catalina 的該方法用于創建一個 Digester 實例,并添加解析 conf/server.xml 的 RuleSet。Digester 原本是 Apache 的一個開源項目,專門解析 XML 文件的,但我看 Tomcat-9.0.0.M22 中直接將這些類整合到 Tomcat 內部了,而不是引入 jar 文件。Digester 工具的原理不在本文的介紹范圍,有興趣的話可以參考 The Digester Component – Apache 或 《How Tomcat works》- Digester [推薦] 一章
- parse() 方法就是 Digester 處理 conf/server.xml 創建各個組件的過程。值的一提的是這些組件都是使用反射的方式來創建的。特別的,在創建 Digester 的時候,添加了一些特別的 rule Set,用于創建一些十分核心的組件,這些組件在 conf/server.xml 中沒有但是其作用都比較大,這里做下簡單介紹,當 Start 時用到了再詳細說明:
- EngineConfig。LifecycleListener 的實現類,觸發 Engine 的生命周期事件后調用,這個監聽器沒有特別大的作用,就是打印一下日志
- HostConfig。LifecycleListener 的實現類,觸發 Host 的生命周期事件后調用。這個監聽器的作用就是部署應用程序,這包括 conf/<Engine>/<Host>/ 目錄下所有的 Context xml 文件 和 webapps 目錄下的應用程序,不管是 war 文件還是已解壓的目錄。 另外后臺進程對應用程序的熱部署也是由該監聽器負責的。
- ContextConfig。LifecycleListener 的實現類,觸發 Context 的生命周期事件時調用。這個監聽器的作用是配置應用程序,它會讀取并合并 conf/web.xml 和 應用程序的 web.xml,分析 /WEB-INF/classes/ 和 /WEB-INF/lib/*.jar中的 Class 文件的注解,將其中所有的 Servlet、ServletMapping、Filter、FilterMapping、Listener 都配置到 StandardContext 中,以備后期使用。當然了 web.xml 中還有一些其他的應用程序參數,最后都會一并配置到 StandardContext 中。
- reconfigureStartStopExecutor() 用于重新配置啟動和停止子容器的 Executor。默認是 1 個線程。我們可以配置 conf/server.xml 中 Engine 的 startStopThreads,來指定用于啟動和停止子容器的線程數量,如果配置 0 的話會使用 Runtime.getRuntime().availableProcessors() 作為線程數,若配置為負數的話會使用 Runtime.getRuntime().availableProcessors() + 配置值,若和小與 1 的話,使用 1 作為線程數。當線程數是 1 時,使用 InlineExecutorService 它直接使用當前線程來執行啟動停止操作,否則使用 ThreadPoolExecutor 來執行,其最大線程數為我們配置的值。
- 需要注意的是 Host 的 init 操作是在 Start 階段來做的, StardardHost 創建好后其 state 屬性的默認值是 LifecycleState.NEW,所以在其調用 startInternal() 之前會進行一次初始化。
Tomcat Start[Deployment]
- 圖中從 StandardHost Start StandardContext 的這步其實在真正的執行流程中會直接跳過,因為 conf/server.xml 文件中并沒有配置任何的 Context,所以在 findChildren() 查找子容器時會返回空數組,所以之后遍歷子容器來啟動子容器的 for 循環就直接跳過了。
- 觸發 Host 的 BEFORE_START_EVENT 生命周期事件,HostConfig 調用其 beforeStart() 方法創建 $CATALINA_BASE/webapps& $CATALINA_BASE/conf/<Engine>/<Host>/ 目錄。
- 觸發 Host 的 START_EVENT 生命周期事件,HostConfig 調用其 start() 方法開始部署已在 $CATALINA_BASE/webapps & $CATALINA_BASE/conf/<Engine>/<Host>/ 目錄下的應用程序。
- 解析 $CATALINA_BASE/conf/<Engine>/<Host>/ 目錄下所有定義 Context 的 XML 文件,并添加到 StandardHost。這些 XML 文件稱為應用程序描述符。正因為如此,我們可以配置一個虛擬路徑來保存應用程序中用到的圖片,詳細的配置過程請參考 開發環境配置指南 – 6.3. 配置圖片存放目錄
- 部署 $CATALINA_BASE/webapps 下所有的 WAR 文件,并添加到 StandardHost。
- 部署 $CATALINA_BASE/webapps 下所有已解壓的目錄,并添加到 StandardHost。
特別的,添加到 StandardHost 時,會直接調用 StandardContext 的 start() 方法來啟動應用程序。啟動應用程序步驟請看 Context Start 一節。
- 在 StandardEngine 和 StandardContext 啟動時都會調用各自的 threadStart() 方法,該方法會創建一個新的后臺線程來處理該該容器和子容器及容器內各組件的后臺事件。StandardEngine 會直接創建一個后臺線程,StandardContext 默認是不創建的,和 StandardEngine 共用同一個。后臺線程處理機制是周期調用組件的 backgroundProcess() 方法。詳情請看 Background process 一節。
- MapperListener
- addListeners(engine) 方法會將該監聽器添加到 StandardEngine 和它的所有子容器中
- registerHost() 會注冊所有的 Host 和他們的子容器到 Mapper 中,方便后期請求處理時使用。
- 當有新的應用(StandardContext)添加進來后,會觸發 Host 的容器事件,然后通過 MapperListener 將新應用的映射注冊到 Mapper 中。
- Start 工作都做完以后 Catalina 會創建一個 CatalinaShutdownHook 并注冊到 JVM。CatalinaShutdownHook 繼承了 Thread,是 Catalina 的內部類。其 run 方法中直接調用了 Catalina 的 stop() 方法來關閉整個服務器。注冊該 Thread 到 JVM 的原因是防止用戶非正常終止 Tomcat,比如直接關閉命令窗口之類的。當直接關閉命令窗口時,操作系統會向 JVM 發送一個終止信號,然后 JVM 在退出前會逐一啟動已注冊的 ShutdownHook 來關閉相應資源。
Context Start
- StandRoot 類實現了 WebResourceRoot 接口,它容納了一個應用程序的所有資源,通俗的來說就是部署到 webapps 目錄下對應 Context 的目錄里的所有資源。因為我對 Tomcat 的資源管理部分暫時不是很感興趣,所以資源管理相關類只是做了簡單了解,并沒有深入研究源代碼。
- resourceStart() 方法會對 StandardRoot 進行初始配置
- postWorkDirectory() 用于創建對應的工作目錄 $CATALINA_BASE/work/<Engine>/<Host>/<Context>, 該目錄用于存放臨時文件。
- StardardContext 只是一個容器,而 ApplicationContext 則是一個應用程序真正的運行環境,相關類及操作會在請求處理流程看完以后進行補充。
- StardardContext 觸發 CONFIGURE_START_EVENT 生命周期事件,ContextConfig 開始調用 configureStart() 對應用程序進行配置。
- 這個過程會解析并合并 conf/web.xml & conf/<Engine>/<Host>/web.xml.default & webapps/<Context>/WEB-INF/web.xml 中的配置。
- 配置配置文件中的參數到 StandardContext, 其中主要的包括 Servlet、Filter、Listener。
- 因為從 Servlet3.0 以后是直接支持注解的,所以服務器必須能夠處理加了注解的類。Tomcat 通過分析 WEB-INF/classes/ 中的 Class 文件和 WEB-INF/lib/ 下的 jar 包將掃描到的 Servlet、Filter、Listerner 注冊到 StandardContext。
- setConfigured(true),是非常關鍵的一個操作,它標識了 Context 的成功配置,若未設置該值為 true 的話,Context 會啟動失敗。
Background process
- 后臺進程的作用就是處理一下 Servlet 引擎中的周期性事件,處理周期默認是 10s。
- 特別的 StandardHost 的 backgroundProcess() 方法會觸發 Host 的 PERIODIC_EVENT 生命周期事件。然后 HostConfig 會調用其 check() 方法對已加載并進行過重新部署的應用程序進行 reload 或對新部署的應用程序進行熱部署。熱部署跟之前介紹的部署步驟一致, reload() 過程只是簡單的順序調用 setPause(true)、stop()、start()、setPause(false),其中 setPause(true) 的作用是暫時停止接受請求。
How to read excellent open source projects
真正的第一次閱讀開源項目源代碼,收獲還是很大的。讓我在架構設計、面向對象思想、設計模式、Clean Code等等各個方面都有了進步。閱讀優秀的開源項目其實是一件很爽的事,因為時不時的會發現一個新的設計思路,然后不由自主的感嘆一聲居然還可以這樣!當然了,讀的時候還是會有一些痛點的,比如說碰到一個變量,但是死活就是找不到初始化的位置,有時通過 Find Usage 工具可以找到,但有些找不到的只能從頭開始再過一邊源碼。有時碰到一個設計思路死活都想不明白為什么這樣設計等等,這種情況就只能通過分析更高一層的架構來解決了等等。
下面我簡單分享一下我是如何閱讀開源項目源碼的。
- 先找一些介紹該項目架構的書籍來看,項目架構是項目核心中的核心,讀架構讀的是高層次的設計思路,讀源碼讀的是低層次的實現細節。有了高層次的設計思路做指導,源碼讀起來才會得心應手,因為讀的時候心里很清楚現在在讀的源碼在整個項目架構中處于什么位置。我在讀 Tomcat 源碼之前先把 《How Tomcat works》 一書過了一邊,然后又看了一下 《Tomcat 架構解析》 的第二章,對 Tomcat 的架構有了初步了解。(PS:《How Tomcat works》一書是全英文的,但讀起來非常流暢,雖然它是基于 Tomcat 4 和 5 的,但 Tomcat 架構沒有非常大的變化,新版的 Tomcat 只是增加了一些組件,如果你要學習 Tomcat 的話,首推這本書!)
- 如果實在找不到講架構的書,那就自己動手畫類圖吧!一般來說,開源項目都是為了提供服務的,我們把提供服務的流程作為主線來分析源代碼,這樣目的性會更強一些,將該流程中涉及到的類畫到類圖中,最后得到的類圖就是架構!不過分析之前你要先找到流程的入口點,否則分析就無從開始。以 Tomcat 為例,他的主線流程大致可以分為 3 個:啟動、部署、請求處理。他們的入口點就是 Bootstrap 類和 接受請求的 Acceptor 類!
- 有了閱讀思路我們下面來說說工具吧。我使用的閱讀工具是 IntelliJ IDEA,一款十分強大的 IDE,可能比較重量級,如果你有其他更加輕量級的 Linux 平臺源碼閱讀工具,可以推薦給我~
- Structure 欄目可以自定義列出類中的域、方法,然后還可以按照繼承結構對域和方法進行分組,這樣就可以直接看出來域和方法是在繼承結構中哪個類里定義的。當你點擊方法和域時,還可以自動滾動到源代碼等等。
- 在源代碼中 點擊右鍵 -> Diagrams -> show Diagram 可以顯示類的繼承結構,圖中包含了該類所有的祖先和所有的接口。在該圖中選擇指定的父類和接口,點擊右鍵 -> show Implementations, IDEA 會列出接口的實現類或該類的子類。
- FindUsage、Go To Declaration 等等就不再多說了。
- 目前想到的就這么多,如果你發現了我沒有提到的功能,歡迎跟我郵件交流~
Reference
- 《How Tomcat works》
- https://www.amazon.com/How-Tomcat-Works-Budi-Kurniawan/dp/097521280X
- 《Tomcat 架構解析》– 劉光瑞
- http://product.dangdang.com/25084132.html
- Tomcat-9.0-doc
- https://tomcat.apache.org/tomcat-9.0-doc/index.html
- apache-tomcat-9.0.0.M22-src
- http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.0.M22/src/
直都在做App開發,但是對java web方面的了解比較少,最近有時間,所以自己就尋思動手從零開始搭建一個java web項目。該項目主要是給app,提供接口服務,簡稱項目為‘mserver’。好了,接下來,我們就開始簡單的搭建項目。
一.開發所需工具。(根據你的電腦以及系統選擇合適的版本下載)
1.JDK 。下載鏈接。
JDK(Java Development Kit) 是 Java 語言的軟件開發工具包(SDK)。JDK是 Java 語言的軟件開發工具包,主要用于移動設備、嵌入式設備上的java應用程序。JDK是整個java開發的核心,它包含了JAVA的運行環境,JAVA工具和JAVA基礎的類庫。
2.eclipse開發工具。下載鏈接。
PS:我們在下載軟件的過程中,可能會有多個不同的下載文件,例如,zip、msi等,那么這兩個有什么區別嗎?
- ZIP是免安裝的軟件包,MSI是微軟特有壓縮格式,是需要安裝的軟件包
- ZIP Archive: 壓縮版本,需要自己配置
- MSI Installer:安裝版本,安裝過程中自動配置
3.Tomcat服務器。下載鏈接。
4.Mysq數據庫。下載鏈接 。
如果你不習慣使用命令去操作數據庫,那么推薦你使用SQLyog工具,下載鏈接。
PS:下載安裝好JDK 后,需要配置環境變量。(以Win7電腦為例,配置環境變量)
(1).依次點擊,計算機→屬性→高級系統設置→高級→環境變量;
(2).打開系統變量,新建JAVA_HOME 變量,變量值填寫jdk的安裝目錄(本人是 D:\Java\jdk1.7.0);
(3).在系統變量中找到Path變量,點擊編輯,
在變量值最后輸入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
(注意原來Path的變量值末尾如果沒有‘;’,先輸入';'后再輸入上面的代碼);
(4).在系統變量中新建 CLASSPATH 變量
變量值填寫 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一點);
經過以上幾步,環境變量就配置完成了。但是,我們還得驗證一下是否配置成功,運行cmd 輸入 java -version,如出現以下截圖顯示的顯示,說明配置成功。
二. 創建項目。
1.打開eclipse,先配置一下Tomcat服務器。
(1).打開windows-> preferences,找到Server下方的Runtime Environment,單擊右方的Add按鈕:
(2). 選擇已經安裝的Tomcat版本,點擊Next,
(3).找到下載安裝后的Tomcat,點擊Finish。
經過以上幾步,就可以看到,紅色框中出現剛才你添加的Tomcat服務器。
2.創建項目。
(1). 打開eclipse,在Workspace空白的地方,右鍵,New,選擇‘Dynamic Web project’,點擊Next,
(2).輸入項目名稱,選擇服務器,其他的默認就可以,點擊Finish就可以了!
稍等一會,你的Eclipse中會出現兩個項目,如下圖所示,表示創建項目成功了。
此時,你可以'run'項目,運行后,可能會報404,這是因為你的web項目底下沒有可訪問的資源。那么就在項目的‘WebContent’目錄底下,創建一個比較簡單的jsp文件index.jsp,具體代碼,如下
- <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
- pageEncoding="ISO-8859-1"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Insert title here</title>
- </head>
- <body>
- <h1>hello world!</h1>
- <h2>This is my test page!</h2>
- <h3>Welcome to my page!</h3>
- </body>
- </html>
創建成功后,點擊運行,然后在瀏覽器中輸入“http://localhost:8080/mServer/index.jsp”,便可以看到,
經過上面兩大步驟,我們的mServer接口項目已經創建成功了,我們就可以開始進行接口開發了!