omcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat 部分是Apache 服务器的扩展,但它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。目前Tomcat最新版本为9.0。
官网下载:https://www.apache.org/
因为下载的是解压版本,解压到相应的位置即可;
TOMCAT的目录结构
o/bin:存放windows或Linux平台上启动和关闭Tomcat的脚本文件
o/conf:存放Tomcat服务器的各种全局配置文件,其中最重要的是server.xml和web.xml
o/doc:存放Tomcat文档
o/server:包含三个子目录:classes、lib和webapps
o/server/lib:存放Tomcat服务器所需的各种JAR文件
o/server/webapps:存放Tomcat自带的两个WEB应用admin应用和 manager应用
o/common/lib:存放Tomcat服务器以及所有web应用都可以访问的jar文件
o/shared/lib:存放所有web应用都可以访问的jar文件(但是不能被Tomcat服务器访问)
o/logs:存放Tomcat执行时的日志文件
o/src:存放Tomcat的源代码
o/webapps:Tomcat的主要Web发布目录,默认情况下把Web应用文件放于此目录
o/work:存放JSP编译后产生的class文件
WEB应用的目录结构:假设在webapps下有mixims的web应用
/mixims:Web应用的根目录,所有的jsp文件和html文件都在此目录下
/mixims/WEB_INF:存放该web应用发布时的描述文件web.xml
/mixims/WEB_INF/class:存放各种class文件,Servlet文件也存放于此目录下
/mixims/WEB_INF/lib:存放各钟Web应用所需要的jar文件。比如可以存放JDBC驱动程序的JAR文件
第一步 打开Eclipse
设置运行环境
创建动态Web项目
为项目创建一个测试主页:
添加tomcat服务
启动服务;
使用内置浏览器打开项目:
至此,简单的Web项目就建立完成了,接下带你去简单部署刚才制作的Web项目!
第一种WAR包方式:
开启tomcat服务
本地浏览器输入http://localhost:8080/AWEI/ 测试Web项目
此时,tomcat 的webapps文件夹内如下:
找到web项目的根目录将其复制到tomcat的webapps文件夹下:如图
并将根目录名称改为项目名称
本地浏览器输入http://localhost:8080/mixims/ 测试Web项目
请点击此处输图片描述
至此,两种部署web项目方法已结束。
本号所有文章都经笔者亲自测验后整理成稿,期间耗费了很多精力,如果有朋友想收录自己的博客中请联系笔者「垒码大叔」;
初入IT世界的小白,欢迎大神留言交流,你的互动,是我成长的动力;
如果觉得分享内容还不错,就推荐到你的朋友圈吧,让更多人一起交流和分享;
一、前言
tomcat官网下载
二、在IntelliJ IDEA配置Tomcat
1.点击Run-Edit Configurations...
idea 配置tomcat
2.选择左侧“+”,选择Tomcat Server--Local
idea -->tomcat -->local
3.在Tomcat Server -> Unnamed -> Server -> Application server项目下,点击 Configuration ,找到本地 Tomcat 服务器,再点击 OK按钮
4.至此,IntelliJ IDEA配置Tomcat完成。
启动Tomcat后,打开浏览器,键入 http://localhost:8080
tomcat 原始启动页面
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 "$@"
整个脚本核心就是最后一句代码, EXECUTABLE变量是catalina.sh, 代表执行catalina.sh, 参数是start, 再去对比了shutdown.sh, 两个脚本的核心都是调用catalina.sh传递的变量不同。
整个脚本很长,我这里之截图了我们关心的脚本内容。 这段代码里, 除了能看到参数传递start, 最后会输出Tomcat started外,能看到调用了org.apache.catalina.startup.Bootstrap, 也就是说找到我们的程序入口,或者说找到了我们的程序的main函数。
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."
看到这里我们做个小小的总结:Tomcat本质上也是一个java程序,因此startup.sh会启动一个jvm来运行tomcat的启动类Bootstrap.java。
开始main方法之前,首先看两个关键属性.
/*************
守护进程对象
**********/
private static volatile Bootstrap daemon = null;
/***
守护程序用的catalina对象
***/
private Object catalinaDaemon = null;
public static void main(String args[]) {
synchronized (daemonLock) {
if (daemon == null) {
//初始化完成之前,不要对daemon赋值
Bootstrap bootstrap = new Bootstrap();
try {
//调用初始化方法, 完成加载器的配置和初始化器的准备
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
//当作为服务正在运行时,如果调用停止方法,这将在一个新线程上进行,以确保使用正确的类加载器,防止出现未找到类的异常
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启动
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 {
//初始化类的三个加载器
initClassLoaders();
//设置线程类加载器, 将容器的加载器传入
Thread.currentThread().setContextClassLoader(catalinaLoader);
//加载安全类加载器
SecurityClassLoad.securityClassLoad(catalinaLoader);
//通过反射加载catalina
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
//创建对象
Object startupInstance = startupClass.getConstructor().newInstance();
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
//将类加载器作为参数传递
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader; //共享加载器
Method method = startupInstance.getClass().getMethod(methodName, paramTypes); //对类加载器进行初始化赋值
//调用catalina类内部的setParentClassLoader方法对catalina类内部的类加载赋值
method.invoke(startupInstance, paramValues);
//将创建好的startupInstance对象赋值给catalinaDaemon
catalinaDaemon = startupInstance;
}
Catalina类的load方法核心就解析config/server.xml并创建Server组件实例, 也就是我们在tomcat整体架构章节里了解的一个tomcat只有一个Server实例。 这部分代码块,我删掉了注释代码,try...catch, 只留下了核心业务代码。
public void load() {
loaded = true;
long t1 = System.nanoTime();
initDirs();
initNaming();
//利用digester类解析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();
//服务器执行初始化 开始调用的Server的初始化方法注意Server是一个接口
getServer().init();
}
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
return;
}
long t1 = System.nanoTime();
//开始一个Server实例
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接口的实现类是StandardServer.
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");
Server接口继承了Lifecycle接口
StandardServer类继承了抽象类LifecycleMBeanBase,同时实现了Server接口
LifecycleMBeanBase抽象类又继承了抽象类LifecycleBase, 而LifecycleBase抽象类又实现了Lifecycle接口
通过前面的调用链看出来Catalina.start会调用Server接口的start方法,而StandardServer实现类的start方法就追溯到了LifeCycleBase抽象的start方法, 这个类里定义了抽象方法startInternal让子类去实现。 在start方法中也调用了startInternal方法。
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
synchronized (servicesLock) {
//这里启动定义的多个service
for (Service service : services) {
service.start();
}
}
}
根据Server的实现类StandardServer类,我顺便查看了其所在包, 看到了整个tomcat用到的核心组件的实现类都在这里了,比如StandardEngine, StandardService,StandardHost, 可以查看其他的实现类结构。
结合上面的两张图片,以及上述的源码分析,我们就能总结出来整个startup.sh过程中完成的任务
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
*请认真填写需求信息,我们会在24小时内与您取得联系。