omcat是Apache 軟件基金會(huì)(Apache Software Foundation)的Jakarta 項(xiàng)目中的一個(gè)核心項(xiàng)目,由Apache、Sun 和其他一些公司及個(gè)人共同開(kāi)發(fā)而成。由于有了Sun 的參與和支持,最新的Servlet 和JSP 規(guī)范總是能在Tomcat 中得到體現(xiàn),Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 規(guī)范。因?yàn)門(mén)omcat 技術(shù)先進(jìn)、性能穩(wěn)定,而且免費(fèi),因而深受Java 愛(ài)好者的喜愛(ài)并得到了部分軟件開(kāi)發(fā)商的認(rèn)可,成為目前比較流行的Web 應(yīng)用服務(wù)器。
Tomcat 服務(wù)器是一個(gè)免費(fèi)的開(kāi)放源代碼的Web 應(yīng)用服務(wù)器,屬于輕量級(jí)應(yīng)用服務(wù)器,在中小型系統(tǒng)和并發(fā)訪問(wèn)用戶(hù)不是很多的場(chǎng)合下被普遍使用,是開(kāi)發(fā)和調(diào)試JSP 程序的首選。對(duì)于一個(gè)初學(xué)者來(lái)說(shuō),可以這樣認(rèn)為,當(dāng)在一臺(tái)機(jī)器上配置好Apache 服務(wù)器,可利用它響應(yīng)HTML(標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言下的一個(gè)應(yīng)用)頁(yè)面的訪問(wèn)請(qǐng)求。實(shí)際上Tomcat 部分是Apache 服務(wù)器的擴(kuò)展,但它是獨(dú)立運(yùn)行的,所以當(dāng)你運(yùn)行tomcat 時(shí),它實(shí)際上作為一個(gè)與Apache 獨(dú)立的進(jìn)程單獨(dú)運(yùn)行的。
訣竅是,當(dāng)配置正確時(shí),Apache 為HTML頁(yè)面服務(wù),而Tomcat 實(shí)際上運(yùn)行JSP 頁(yè)面和Servlet。另外,Tomcat和IIS等Web服務(wù)器一樣,具有處理HTML頁(yè)面的功能,另外它還是一個(gè)Servlet和JSP容器,獨(dú)立的Servlet容器是Tomcat的默認(rèn)模式。不過(guò),Tomcat處理靜態(tài)HTML的能力不如Apache服務(wù)器。目前Tomcat最新版本為9.0。
官網(wǎng)下載:https://www.apache.org/
因?yàn)橄螺d的是解壓版本,解壓到相應(yīng)的位置即可;
TOMCAT的目錄結(jié)構(gòu)
o/bin:存放windows或Linux平臺(tái)上啟動(dòng)和關(guān)閉Tomcat的腳本文件
o/conf:存放Tomcat服務(wù)器的各種全局配置文件,其中最重要的是server.xml和web.xml
o/doc:存放Tomcat文檔
o/server:包含三個(gè)子目錄:classes、lib和webapps
o/server/lib:存放Tomcat服務(wù)器所需的各種JAR文件
o/server/webapps:存放Tomcat自帶的兩個(gè)WEB應(yīng)用admin應(yīng)用和 manager應(yīng)用
o/common/lib:存放Tomcat服務(wù)器以及所有web應(yīng)用都可以訪問(wèn)的jar文件
o/shared/lib:存放所有web應(yīng)用都可以訪問(wèn)的jar文件(但是不能被Tomcat服務(wù)器訪問(wèn))
o/logs:存放Tomcat執(zhí)行時(shí)的日志文件
o/src:存放Tomcat的源代碼
o/webapps:Tomcat的主要Web發(fā)布目錄,默認(rèn)情況下把Web應(yīng)用文件放于此目錄
o/work:存放JSP編譯后產(chǎn)生的class文件
WEB應(yīng)用的目錄結(jié)構(gòu):假設(shè)在webapps下有mixims的web應(yīng)用
/mixims:Web應(yīng)用的根目錄,所有的jsp文件和html文件都在此目錄下
/mixims/WEB_INF:存放該web應(yīng)用發(fā)布時(shí)的描述文件web.xml
/mixims/WEB_INF/class:存放各種class文件,Servlet文件也存放于此目錄下
/mixims/WEB_INF/lib:存放各鐘Web應(yīng)用所需要的jar文件。比如可以存放JDBC驅(qū)動(dòng)程序的JAR文件
第一步 打開(kāi)Eclipse
設(shè)置運(yùn)行環(huán)境
創(chuàng)建動(dòng)態(tài)Web項(xiàng)目
為項(xiàng)目創(chuàng)建一個(gè)測(cè)試主頁(yè):
添加tomcat服務(wù)
啟動(dòng)服務(wù);
使用內(nèi)置瀏覽器打開(kāi)項(xiàng)目:
至此,簡(jiǎn)單的Web項(xiàng)目就建立完成了,接下帶你去簡(jiǎn)單部署剛才制作的Web項(xiàng)目!
第一種WAR包方式:
開(kāi)啟tomcat服務(wù)
本地瀏覽器輸入http://localhost:8080/AWEI/ 測(cè)試Web項(xiàng)目
此時(shí),tomcat 的webapps文件夾內(nèi)如下:
找到web項(xiàng)目的根目錄將其復(fù)制到tomcat的webapps文件夾下:如圖
并將根目錄名稱(chēng)改為項(xiàng)目名稱(chēng)
本地瀏覽器輸入http://localhost:8080/mixims/ 測(cè)試Web項(xiàng)目
請(qǐng)點(diǎn)擊此處輸圖片描述
至此,兩種部署web項(xiàng)目方法已結(jié)束。
本號(hào)所有文章都經(jīng)筆者親自測(cè)驗(yàn)后整理成稿,期間耗費(fèi)了很多精力,如果有朋友想收錄自己的博客中請(qǐng)聯(lián)系筆者「壘碼大叔」;
初入IT世界的小白,歡迎大神留言交流,你的互動(dòng),是我成長(zhǎng)的動(dòng)力;
如果覺(jué)得分享內(nèi)容還不錯(cuò),就推薦到你的朋友圈吧,讓更多人一起交流和分享;
一、前言
tomcat官網(wǎng)下載
二、在IntelliJ IDEA配置Tomcat
1.點(diǎn)擊Run-Edit Configurations...
idea 配置tomcat
2.選擇左側(cè)“+”,選擇Tomcat Server--Local
idea -->tomcat -->local
3.在Tomcat Server -> Unnamed -> Server -> Application server項(xiàng)目下,點(diǎn)擊 Configuration ,找到本地 Tomcat 服務(wù)器,再點(diǎn)擊 OK按鈕
4.至此,IntelliJ IDEA配置Tomcat完成。
啟動(dòng)Tomcat后,打開(kāi)瀏覽器,鍵入 http://localhost:8080
tomcat 原始啟動(dòng)頁(yè)面
os400=false
case "`uname`" in
OS400*) os400=true;;
esac
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh
if $os400; then
eval
else
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
echo "Cannot find $PRGDIR/$EXECUTABLE"
echo "The file is absent or does not have execute permission"
echo "This file is needed to run this program"
exit 1
fi
fi
exec "$PRGDIR"/"$EXECUTABLE" start "$@"
整個(gè)腳本核心就是最后一句代碼, EXECUTABLE變量是catalina.sh, 代表執(zhí)行catalina.sh, 參數(shù)是start, 再去對(duì)比了shutdown.sh, 兩個(gè)腳本的核心都是調(diào)用catalina.sh傳遞的變量不同。
整個(gè)腳本很長(zhǎng),我這里之截圖了我們關(guān)心的腳本內(nèi)容。 這段代碼里, 除了能看到參數(shù)傳遞start, 最后會(huì)輸出Tomcat started外,能看到調(diào)用了org.apache.catalina.startup.Bootstrap, 也就是說(shuō)找到我們的程序入口,或者說(shuō)找到了我們的程序的main函數(shù)。
shift
eval $_NOHUP "\"$_RUNJAVA\"" "\"$CATALINA_LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-classpath "\"$CLASSPATH\"" \
-Djava.security.manager \
-Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \
-Dcatalina.base="\"$CATALINA_BASE\"" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
org.apache.catalina.startup.Bootstrap "$@" start \
>> "$CATALINA_OUT" 2>&1 "&"
else
eval $_NOHUP "\"$_RUNJAVA\"" "\"$CATALINA_LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-classpath "\"$CLASSPATH\"" \
-Dcatalina.base="\"$CATALINA_BASE\"" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
org.apache.catalina.startup.Bootstrap "$@" start \
>> "$CATALINA_OUT" 2>&1 "&"
fi
if [ ! -z "$CATALINA_PID" ]; then
echo $! > "$CATALINA_PID"
fi
echo "Tomcat started."
看到這里我們做個(gè)小小的總結(jié):Tomcat本質(zhì)上也是一個(gè)java程序,因此startup.sh會(huì)啟動(dòng)一個(gè)jvm來(lái)運(yùn)行tomcat的啟動(dòng)類(lèi)Bootstrap.java。
開(kāi)始main方法之前,首先看兩個(gè)關(guān)鍵屬性.
/*************
守護(hù)進(jìn)程對(duì)象
**********/
private static volatile Bootstrap daemon = null;
/***
守護(hù)程序用的catalina對(duì)象
***/
private Object catalinaDaemon = null;
public static void main(String args[]) {
synchronized (daemonLock) {
if (daemon == null) {
//初始化完成之前,不要對(duì)daemon賦值
Bootstrap bootstrap = new Bootstrap();
try {
//調(diào)用初始化方法, 完成加載器的配置和初始化器的準(zhǔn)備
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
//當(dāng)作為服務(wù)正在運(yùn)行時(shí),如果調(diào)用停止方法,這將在一個(gè)新線程上進(jìn)行,以確保使用正確的類(lèi)加載器,防止出現(xiàn)未找到類(lèi)的異常
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
//Bootstrap加載
daemon.load(args);
//Bootstrap啟動(dòng)
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
}
}
//Bootstrap.init
public void init() throws Exception {
//初始化類(lèi)的三個(gè)加載器
initClassLoaders();
//設(shè)置線程類(lèi)加載器, 將容器的加載器傳入
Thread.currentThread().setContextClassLoader(catalinaLoader);
//加載安全類(lèi)加載器
SecurityClassLoad.securityClassLoad(catalinaLoader);
//通過(guò)反射加載catalina
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
//創(chuàng)建對(duì)象
Object startupInstance = startupClass.getConstructor().newInstance();
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
//將類(lèi)加載器作為參數(shù)傳遞
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader; //共享加載器
Method method = startupInstance.getClass().getMethod(methodName, paramTypes); //對(duì)類(lèi)加載器進(jìn)行初始化賦值
//調(diào)用catalina類(lèi)內(nèi)部的setParentClassLoader方法對(duì)catalina類(lèi)內(nèi)部的類(lèi)加載賦值
method.invoke(startupInstance, paramValues);
//將創(chuàng)建好的startupInstance對(duì)象賦值給catalinaDaemon
catalinaDaemon = startupInstance;
}
Catalina類(lèi)的load方法核心就解析config/server.xml并創(chuàng)建Server組件實(shí)例, 也就是我們?cè)趖omcat整體架構(gòu)章節(jié)里了解的一個(gè)tomcat只有一個(gè)Server實(shí)例。 這部分代碼塊,我刪掉了注釋代碼,try...catch, 只留下了核心業(yè)務(wù)代碼。
public void load() {
loaded = true;
long t1 = System.nanoTime();
initDirs();
initNaming();
//利用digester類(lèi)解析server.xml,得到容器的配置
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
if (inputStream == null) {
inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());
inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());
}
if (inputStream == null) {
inputStream = getClass().getClassLoader().getResourceAsStream("server-embed.xml");
inputSource = new InputSource(getClass().getClassLoader().getResource("server-embed.xml").toString());
}
if (inputStream == null || inputSource == null) {
return;
}
try {
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
} catch (SAXParseException spe) {
return;
} catch (Exception e) {
return;
}
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
initStreams();
//服務(wù)器執(zhí)行初始化 開(kāi)始調(diào)用的Server的初始化方法注意Server是一個(gè)接口
getServer().init();
}
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
return;
}
long t1 = System.nanoTime();
//開(kāi)始一個(gè)Server實(shí)例
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
}
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(false);
}
}
if (await) {
await();
stop();
}
}
從Bootstrap#createStartDigester方法中可以看到Server接口的實(shí)現(xiàn)類(lèi)是StandardServer.
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");
Server接口繼承了Lifecycle接口
StandardServer類(lèi)繼承了抽象類(lèi)LifecycleMBeanBase,同時(shí)實(shí)現(xiàn)了Server接口
LifecycleMBeanBase抽象類(lèi)又繼承了抽象類(lèi)LifecycleBase, 而LifecycleBase抽象類(lèi)又實(shí)現(xiàn)了Lifecycle接口
通過(guò)前面的調(diào)用鏈看出來(lái)Catalina.start會(huì)調(diào)用Server接口的start方法,而StandardServer實(shí)現(xiàn)類(lèi)的start方法就追溯到了LifeCycleBase抽象的start方法, 這個(gè)類(lèi)里定義了抽象方法startInternal讓子類(lèi)去實(shí)現(xiàn)。 在start方法中也調(diào)用了startInternal方法。
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
synchronized (servicesLock) {
//這里啟動(dòng)定義的多個(gè)service
for (Service service : services) {
service.start();
}
}
}
根據(jù)Server的實(shí)現(xiàn)類(lèi)StandardServer類(lèi),我順便查看了其所在包, 看到了整個(gè)tomcat用到的核心組件的實(shí)現(xiàn)類(lèi)都在這里了,比如StandardEngine, StandardService,StandardHost, 可以查看其他的實(shí)現(xiàn)類(lèi)結(jié)構(gòu)。
結(jié)合上面的兩張圖片,以及上述的源碼分析,我們就能總結(jié)出來(lái)整個(gè)startup.sh過(guò)程中完成的任務(wù)
https://juejin.cn/post/7155750621864263716
https://2i3i.com/tomcat-code-3.html
https://juejin.cn/post/7082681444182523934
https://time.geekbang.org/column/article/97603
https://zhuanlan.zhihu.com/p/344635709
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。