使用 Docker 搭建 Java Web 运行环境(JDK + TOMCAT) , 方式二,使用Dockerfile

 docker  使用 Docker 搭建 Java Web 运行环境(JDK + TOMCAT) , 方式二,使用Dockerfile已关闭评论
11月 142018
 

原文:https://blog.csdn.net/yjk13703623757/article/details/68944549 

Dockerfile文件内容

# 版本信息
FROM centos
MAINTAINER locutus “locutus@foxmail.com”

# OS环境配置
RUN yum install -y wget

# 安装JDK
RUN mkdir /var/tmp/jdk
RUN wget –no-check-certificate –no-cookies –header “Cookie: oraclelicense=accept-securebackup-cookie”  -P /var/tmp/jdk http://download.oracle.com/otn-pub/java/jdk/8u111-b14/jdk-8u111-linux-x64.tar.gz
RUN tar xzf /var/tmp/jdk/jdk-8u111-linux-x64.tar.gz -C /var/tmp/jdk && rm -rf /var/tmp/jdk/jdk-8u111-linux-x64.tar.gz

# 安装tomcat
RUN mkdir /var/tmp/tomcat
RUN wget -P  /var/tmp/tomcat http://archive.apache.org/dist/tomcat/tomcat-8/v8.5.8/bin/apache-tomcat-8.5.8.tar.gz
RUN tar xzf /var/tmp/tomcat/apache-tomcat-8.5.8.tar.gz -C /var/tmp/tomcat && rm -rf /var/tmp/tomcat/apache-tomcat-8.5.8.tar.gz

#设置环境变量
ENV JAVA_HOME /var/tmp/jdk/jdk1.8.0_111
ENV CATALINA_HOME /var/tmp/tomcat/apache-tomcat-8.5.8
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin

#打包项目并拷贝到tomcat webapps目录
RUN mkdir /var/tmp/webapp
ADD ./  /var/tmp/webapp
RUN cd  /var/tmp/webapp  && cp /var/tmp/webapp/war/sm_new.war /var/tmp/tomcat/apache-tomcat-8.5.8/webapps/

#开启内部服务端口
EXPOSE 8080

#启动tomcat服务器
CMD [“./var/tmp/tomcat/apache-tomcat-8.5.8/bin/catalina.sh”,”run”] && tail -f /var/tmp/tomcat/apache-tomcat-8.5.8/logs/catalina.out 

使用Dockerfile构建镜像

# docker build -t tomcat .    

. 表示Dockerfile在当前文件夹下,也可使用绝对路径(/path/to/Dockerfile)来表示

运行容器
# docker run -it -p 12345:8080 –name=tomcat-test  tomcat 
1
然后在命令行键入 Ctrl + p , Ctrl + q,使容器在后台运行

使用 Docker 搭建 Java Web 运行环境(JDK + TOMCAT) , 方式一

 docker  使用 Docker 搭建 Java Web 运行环境(JDK + TOMCAT) , 方式一已关闭评论
11月 142018
 

转自:https://www.cnblogs.com/zengkefu/p/5667046.html

Docker 是 2014 年最为火爆的技术之一,几乎所有的程序员都听说过它。Docker 是一种“轻量级”容器技术,它几乎动摇了传统虚拟化技术的地位,现在国内外已经有越来越多的公司开始逐步使用 Docker 来替换现有的虚拟化平台了。作为一名 Java 程序员,我们是时候一起把 Docker 学起来了!

本文会对虚拟化技术与 Docker 容器技术做一个对比,然后引出一些 Docker 的名词术语,比如:容器、镜像等,随后将使用 Docker 搭建一个 Java Web 运行环境,最后将对本文做一个总结。

我们先来回顾一下传统虚拟化技术的体系架构:

 

可见,我们在宿主机的操作系统上,可安装了多个虚拟机,而在每个虚拟机中,通过虚拟化技术,实现了一个虚拟操作系统,随后,就可以在该虚拟操作系统上,安装自己所需的应用程序了。这一切看似非常简单,但其中的技术细节是相当高深莫测的,大神级人物都不一定说得清楚。

凡是使用过虚拟机的同学,应该都知道,启动虚拟机就像启动一台计算机,初始化过程是相当慢的,我们需要等很久,才能看到登录界面。一旦虚拟机启动以后,就可以与宿主机建立网络连接,确保虚拟机与宿主机之间是互联互通的。不同的虚拟机之间却是相互隔离的,也就是说,彼此并不知道对方的存在,但每个虚拟机占用的都是宿主机的硬件与网络资源。

我们再来对比一下 Docker 技术的体系架构吧:

 

可见,在宿主机的操作系统上,有一个 Docker 服务在运行(或者称为“Docker 引擎”),在此服务上,我们可开启多个 Docker 容器,而每个 Docker 容器中可运行自己所需的应用程序,Docker 容器之间也是相互隔离的,同样地,都是占用的宿主机的硬件与网络资源。

Docker 容器相对于虚拟机而言,除了在技术实现上完全不一样以外,启动速度较虚拟机而言有本质的飞跃,启动一个容器只在眨眼瞬间。不管是虚拟机还是 Docker 容器,它们都是为了隔离应用程序的运行环境,节省我们的硬件资源,为我们开发人员提供福利。

我们再来看看 Docker 的 Logo 吧:

 

很明显,这是一只鲸鱼,它托着许多集装箱。我们可以把宿主机可当做这只鲸鱼,把相互隔离的容器可看成集装箱,每个集装箱中都包含自己的应用程序。这 Logo 简直的太形象了!

需要强调的是,笔者并非否定虚拟化技术,而是想通过本文让更多的读者了解如何使用 Docker 技术,让大家知道除了虚拟化技术以外,还有另一种替代技术,也能让应用程序隔离起来。

下面,我们将结合一个 Java Web 应用的部署过程,来描述如何“烹饪”Docker 这份美味佳肴。您准备好了吗?我们现在就开始!

原料

前提条件

首先,您要准备一个 CentOS 的操作系统,虚拟机也行。总之,可以通过 Linux 客户端工具访问到 CentOS 操作系统就行。

需要说明的是,Ubuntu 或其它 Linux 操作系统也能玩 Docker,只不过本文选择了以 CentOS 为例,仅此而已。

CentOS 具体要求如下:

  1. 必须是 64 位操作系统
  2. 建议内核在 3.8 以上

通过以下命令查看您的 CentOS 内核:

uname -r

如果执行以上命令后,输出的内核版本号低于 3.8,请参考下面的方法来来升级您的 Linux 内核。

对于 CentOS 6.5 而言,内核版本默认是 2.6。首先,可通过以下命令安装最新内核:

rpm –import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -ivh http://www.elrepo.org/elrepo-release-6-5.el6.elrepo.noarch.rpm
yum -y –enablerepo=elrepo-kernelinstall kernel-lt

随后,编辑以下配置文件:

vi /etc/grub.conf

将default=1修改为default=0。

最后,通过reboot命令重启操作系统。

重启后如果不出意外的话,再次查看内核,您的 CentOS 内核将会显示为 3.10。

如果到这里,您和我们所期望的结果是一致的。恭喜您!下面我们就一起来安装 Docker 了。

安装 Docker

只需通过以下命令即可安装 Docker 软件:

rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
yum -yinstall docker-io

可使用以下命令,查看 Docker 是否安装成功:

docker version

若输出了 Docker 的版本号,则说明安装成功了,可通过以下命令启动 Docker 服务:

service docker start

一旦 Docker 服务启动完毕,我们下面就可以开始使用 Docker 了。

做法

就像曾经安装软件一样,我们首先需要有一张刻录了该软件的光盘,如果您使用的是虚拟光驱,那么就需要运行一种名为“镜像”的文件,通过它来安装软件。在 Docker 的世界里,也有一个名为“镜像”的东西,已经安装我们所需的操作系统,我们一般成为“Docker 镜像”,本文简称“镜像”。

那么问题来了,我们从哪里下载镜像呢?

Docker 官网 确实已经提供了所有的镜像下载地址,可惜在国内却是无法访问的。幸好国内好心人提供了一个 Docker 中文网,在该网站上可以下载我们所需的 Docker 镜像。

下载镜像

我们不妨还是以 CentOS 为例,通过以下步骤,下载一个 CentOS 的镜像。

首先,访问 Docker 中文网,在首页中搜索名为“centos”的镜像,在搜索的结果中,有一个“官方镜像”,它就是我们所需的。

然后,进入 CentOS 官方镜像页面,在“Pull this repository”输入框中,有一段命令,把它复制下来,在自己的命令行上运行该命令,随后将立即下载该镜像。

最后,使用以下命令查看本地所有的镜像:

docker images

当下载完成后,您应该会看到:

REPOSITORY                TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
docker.cn/docker/centos   centos6             25c5298b1a36        7 weeks ago         215.8 MB

如果看到以上输出,说明您可以使用“docker.cn/docker/centos”这个镜像了,或将其称为仓库(Repository),该镜像有一个名为“centos6”的标签(Tag),此外还有一个名为“25c5298b1a36 ”的镜像 ID(可能您所看到的镜像 ID 与此处的不一致,那是正常现象,因为这个数字是随机生成的)。此外,我们可以看到该镜像只有 215.8 MB,非常小巧,而不像虚拟机的镜像文件那样庞大。

现在镜像已经有了,我们下面就需要使用该镜像,来启动容器。

启动容器

容器是在镜像的基础上来运行的,一旦容器启动了,我们就可以登录到容器中,安装自己所需的软件或应用程序。既然镜像已经下载到本地,那么如何才能启动容器呢?

只需使用以下命令即可启动容器:

docker run -i -t -v /root/software/:/mnt/software/ 25c5298b1a36/bin/bash

这条命令比较长,我们稍微分解一下,其实包含以下三个部分:

docker run <相关参数> <镜像 ID> <初始命令>

其中,相关参数包括:

  • -i:表示以“交互模式”运行容器
  • -t:表示容器启动后会进入其命令行
  • -v:表示需要将本地哪个目录挂载到容器中,格式:-v <宿主机目录>:<容器目录>

假设我们的所有安装程序都放在了宿主机的/root/software/目录下,现在需要将其挂载到容器的/mnt/software/目录下。

需要说明的是,不一定要使用“镜像 ID”,也可以使用“仓库名:标签名”,例如:docker.cn/docker/centos:centos6。

初始命令表示一旦容器启动,需要运行的命令,此时使用“/bin/bash”,表示什么也不做,只需进入命令行即可。

安装相关软件

为了搭建 Java Web 运行环境,我们需要安装 JDK 与 Tomcat,下面的过程均在容器内部进行。我们不妨选择/opt/目录作为安装目录,首先需要通过cd /opt/命令进入该目录。

安装 JDK

首先,解压 JDK 程序包:

tar -zxf/mnt/software/jdk-7u67-linux-x64.tar.gz -C .

然后,重命名 JDK 目录:

mv jdk1.7.0_67/ jdk/

安装 Tomcat

首先,解压 Tomcat 程序包:

tar -zxf/mnt/software/apache-tomcat-7.0.55.tar.gz -C .

然后,重命名 Tomcat 目录:

mv apache-tomcat-7.0.55/ tomcat/

设置环境变量

首先,编辑.bashrc文件

vi ~/.bashrc

然后,在该文件末尾添加如下配置:

export JAVA_HOME=/opt/jdk
export PATH=$PATH:$JAVA_HOME

最后,需要使用source命令,让环境变量生效:

source ~/.bashrc

编写运行脚本

我们需要编写一个运行脚本,当启动容器时,运行该脚本,启动 Tomcat,具体过程如下:

首先,创建运行脚本:

vi /root/run.sh

然后,编辑脚本内容如下:

#!/bin/bash
source ~/.bashrc
sh/opt/tomcat/bin/catalina.sh run

注意:这里必须先加载环境变量,然后使用 Tomcat 的运行脚本来启动 Tomcat 服务。

最后,为运行脚本添加执行权限:

chmod u+x/root/run.sh

退出容器

当以上步骤全部完成后,可使用exit命令,退出容器。

随后,可使用如下命令查看正在运行的容器:

dockerps

此时,您应该看不到任何正在运行的程序,因为刚才已经使用exit命令退出的容器,此时容器处于停止状态,可使用如下命令查看所有容器:

dockerps -a

输出如下内容:

CONTAINER ID        IMAGE                             COMMAND             CREATED             STATUS                      PORTS               NAMES
57c312bbaad1        docker.cn/docker/centos:centos6  “/bin/bash”         27 minutes ago      Exited (0) 19 seconds ago                       naughty_goldstine

记住以上CONTAINER ID(容器 ID),随后我们将通过该容器,创建一个可运行 Java Web 的镜像。

创建 Java Web 镜像

使用以下命令,根据某个“容器 ID”来创建一个新的“镜像”:

docker commit 57c312bbaad1 huangyong/javaweb:0.1

该容器的 ID 是“57c312bbaad1”,所创建的镜像名是“huangyong/javaweb:0.1”,随后可使用镜像来启动 Java Web 容器。

启动 Java Web 容器

有必要首先使用docker images命令,查看当前所有的镜像:

REPOSITORY                TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
huangyong/javaweb         0.1                 fc826a4706af        38 seconds ago      562.8 MB
docker.cn/docker/centos   centos6             25c5298b1a36        7 weeks ago         215.8 MB

可见,此时已经看到了最新创建的镜像“huangyong/javaweb:0.1”,其镜像 ID 是“fc826a4706af”。正如上面所描述的那样,我们可以通过“镜像名”或“镜像 ID”来启动容器,与上次启动容器不同的是,我们现在不再进入容器的命令行,而是直接启动容器内部的 Tomcat 服务。此时,需要使用以下命令:

docker run -d -p 58080:8080 –name javaweb huangyong/javaweb:0.1/root/run.sh

稍作解释:

  • -d:表示以“守护模式”执行/root/run.sh脚本,此时 Tomcat 控制台不会出现在输出终端上。
  • -p:表示宿主机与容器的端口映射,此时将容器内部的 8080 端口映射为宿主机的 58080 端口,这样就向外界暴露了 58080 端口,可通过 Docker 网桥来访问容器内部的 8080 端口了。
  • –name:表示容器名称,用一个有意义的名称命名即可。

关于 Docker 网桥的内容,需要补充说明一下。实际上 Docker 在宿主机与容器之间,搭建了一座网络通信的桥梁,我们可通过宿主机 IP 地址与端口号来映射容器内部的 IP 地址与端口号,

在一系列参数后面的是“镜像名”或“镜像 ID”,怎么方便就怎么来。最后是“初始命令”,它是上面编写的运行脚本,里面封装了加载环境变量并启动 Tomcat 服务的命令。

当运行以上命令后,会立即输出一长串“容器 ID”,我们可通过docker ps命令来查看当前正在运行的容器。

CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS                     NAMES
82f47923f926        huangyong/javaweb:0.1  “/root/run.sh”      4 seconds ago       Up 3 seconds        0.0.0.0:58080->8080/tcp   javaweb

品尝

在浏览器中,输入以下地址,即可访问 Tomcat 首页:

http://192.168.65.132:58080/

注意:这里使用的是宿主机的 IP 地址,与对外暴露的端口号 58080,它映射容器内部的端口号 8080。

总结

通过本文,我们了解了 Docker 是什么?它与虚拟机的差别在哪里?以及如何安装 Docker?如何下载 Docker 镜像?如何运行 Docker 容器?如何在容器内安装应用程序?如何在容器上创建镜像?如何以服务的方式启动容器?这一切看似简单,但操作也是相当繁琐的,不过熟能生巧,需要我们不断地操练。

除了这种手工生成 Docker 镜像的方式以外,还有一种更像是写代码一样,可以自动地创建 Docker 镜像的方式。只需要我们编写一个 Dockerfile 文件,随后使用docker build命令即可完成以上所有的手工操作。

tomcat 安装配置apr

 tomcat  tomcat 安装配置apr已关闭评论
12月 302016
 

tomcat的运行模式有3种.修改他们的运行模式.3种模式的运行是否成功,可以看他的启动控制台,或者启动日志.或者登录他们的默认页面http://localhost:8080/查看其中的服务器状态。 

1)bio 

默认的模式,性能非常低下,没有经过任何优化处理和支持. 

2)nio 

利用java的异步io护理技术,no blocking IO技术. 

想运行在该模式下,直接修改server.xml里的Connector节点,修改protocol为 

 <Connector port="80" protocol="org.apache.coyote.http11.Http11NioProtocol" 
	connectionTimeout="20000" 
	URIEncoding="UTF-8" 
	useBodyEncodingForURI="true" 
	enableLookups="false" 
	redirectPort="8443" /> 

启动后,就可以生效。 

3)apr 

安装起来最困难,但是从操作系统级别来解决异步的IO问题,大幅度的提高性能. 

必须要安装apr和native,直接启动就支持apr。下面的修改纯属多余,仅供大家扩充知识,但仍然需要安装apr和native 

如nio修改模式,修改protocol为org.apache.coyote.http11.Http11AprProtoco

tomcat如何支持apr?

需要安装apr, apr-util,   openssl, tomcat-native(tomcat-native包在tomcat目录的bin目录下就有源码的压缩包,解压这个包,注意下版本,也可以在http://tomcat.apache.org/download-native.cgi下载,并在http://tomcat.apache.org/native-doc/miscellaneous/changelog.html中查看下支持的openssl和apr版本,然后到对应的网站下载适合的版本)

1. 从网站 http://apache.spd.co.il/apr/ 中下载apr-xxx.tar.gz

tar zxvf apr-1.xx.xx.tar.gz

cd apr-xxx

./configure

make && make install

默认安装在/usr/local/apr目录下,可以通过命令行参数 –prefix 指定,建议不要改。

2. 从网站 http://apache.spd.co.il/apr/ 中下载apr-util-xxx.tar.gz

tar zxvf apr-util-xxx.tar.gz

cd apr-util-xxx

./configure –with-apr=/usr/local/apr     (此处路径就是上面俺转apr的路径)

make && make install


3.  openssl安装,其实linux版本一般都自带openssl,可以通过命令: openssl version查看版本,如果太低,可以

https://www.openssl.org/source/下载openssl-xx.tar.gz包编译安装

tar zxvf openssl-xx.tar.gz

cd openssl-xx

./config

make && make install (默认安装在/usr/local/ssl/)


4.  安装tomcat-native ,建议使用tomcat自己bin目录下的tomcat-native.tar.gz,

 解压, 

tomcat-native-1.1.27-src的版本进入jni/native目录,查看 BUILDING文件,可以有详细的说明

tomcat-native-1.2.10-src的版本直接进入native目录,查看BUILDING文件,有详细的说明

在native目录下,输入

configure –with-apr=/usr/local/apr –with-ssl=/usr/local/ssl  

其中/usr/local/apr 和 /usr/local/ssl分别是上面安装的apr和openssl目录。

安装完成有提示文字告诉你安装到的位置, 上面路径默认安装在/usr/local/apr/lib


配置tomcat,其实在BUILDING文件有说明,具体是:

Using it in Tomcat
——————

1. In <Connector> use of conf/server.xml:
   protocol=”org.apache.coyote.http11.Http11AprProtocol”
2. In bin/setenv.sh add the following:
   CATALINA_OPTS=”$CATALINA_OPTS -Djava.library.path=/usr/local/apr/lib”
   

 tomcat下没有bin/setenv.sh 文件就新建一个,并有可执行权。



启动tomcat , 看到如下信息: 

信息: Starting ProtocolHandler [“http-apr-8080”]

成功!

关于openssl配置(单向):

单向SSL的概念:

客户端向服务器发送消息,服务器接到消息后,用服务器端的密钥库中的私钥对数据进行加密,然后把加密后的数据和服务器端的公钥一起发送到客户端,客户端用服务器发送来的公钥对数据解密,然后在用传到客户端的服务器公钥对数据加密传给服务器端,服务器用私钥对数据进行解密,这就完成了客户端和服务器之间通信的安全问题,但是单向认证没有验证客户端的合法性。

 

不使用apr情况:

(1)产生密钥库
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 1024 -validity 365 -keystore /usr/local/apache-tomcat-6.0.18/keystore

(2)在Connector上配置密钥库
<Connector port=”8443″ protocol=”HTTP/1.1″ SSLEnabled=”true”
               maxThreads=”150″ scheme=”https” secure=”true”
               clientAuth=”false” sslProtocol=”TLS” keystoreFile=”/usr/local/tomcat/conf/keystore” keystorePass=”123456″/>

 

使用apr情况:

(1)产生密钥库

openssl genrsa -out rsa-private-key.pem 1024
openssl req -new -x509 -nodes -sha1 -days 365 -key rsa-private-key.pem -out self-signed-cert.pem

(2)在Connector上配置密钥库

<Connector port=”8443″ protocol=”HTTP/1.1″ SSLEnabled=”true”
               maxThreads=”150″ scheme=”https” secure=”true”
               clientAuth=”false” sslProtocol=”TLS” 
               SSLCertificateKeyFile=”/usr/local/tomat/rsa-private-key.pem”
               SSLCertificateFile=”/usr/local/tomat/self-signed-cert.pem”/>

 

出现:

Failed to initialize end point associated with ProtocolHandler ["http-apr-8443"]
java.lang.Exception: Connector attribute SSLCertificateFile must be defined when using SSL with APR

可以将: protocol=“HTTP/1.1″修改为  protocol=”org.apache.coyote.http11.Http11Protocol”, 之修改https的端口,不要修改原来支持apr的http的protocol

Intellj IDEA中发布应用, (exploded): Server is not connected. Deploy is not available.问题解决

 tomcat  Intellj IDEA中发布应用, (exploded): Server is not connected. Deploy is not available.问题解决已关闭评论
12月 302016
 

Intellj IDEA中发布应用到tomcat中 出现如下提示:Artifact Gradle : xx.xx : xx.war (exploded): Server (exploded): Server is not connected. Deploy is not available

分析:

由于IDE会设置 JVM 启动参数JAVA_OPTS用于JMX的监听,而启动的tomcat中对JAVA_OPTS有配置参数(比如在setenv.sh/ catalina.sh/ startup,sh), 而且在写参数的过程中使用了下面的写法:


比如在setenv.sh文件中:

错误写法:

export JAVA_OPTS="-XX:MaxPermSize=512m -Xmx1024m"

正确写法:

export JAVA_OPTS="$JAVA_OPTS -XX:MaxPermSize=512m -Xmx1024m"

记得加上

$JAVA_OPTS

这样就不会覆盖了, done。


网上所谓的删除setenv,sh文件方法只是治标不治本。

关于tomcat下无法生成localhost、manage等logging.properties中配置文件问题解决

 tomcat  关于tomcat下无法生成localhost、manage等logging.properties中配置文件问题解决已关闭评论
12月 092016
 

今日有同事提到某机器的tomcat启动后无法产生localhost文件,但catalina.out和localhost.access等访问文件却都可以产生,奇怪了。

比较可以产生和不能产生的两台机器,发现logging.properties等配置都是一样的,但就是logging.properties配置的文件似乎都无法产生,后来经过排查,发现classpath不同, 在不能产生localhost文件的机器上的classpath前多了一些类似“ /usr/local/jdk/lib:/usr/local/jdk/jre/lib ” 的数据。

原来运维为了配置环境变量,在tomcat的bin目录下添加了一个setenv.sh的配置文件,这个文件在catalina.sh运行时会判断如果有这个文件就会执行(见catalina.sh文件), 而setenv.sh配置了这样语句命令export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib。删除这条命令即可, 或者不要使用自定义的setenv.sh。

问题分析:

打开catalina.sh文件, 可以看到tomcat在启动时在catalina.sh中实际会给classpath添加 tomcat-juli.jar包,这个jar包用于解析logging.properties并生成对应的文件如:localhost、manager等文件, 但在如果在classpath中配置了jdk/jre的lib路径, 并且配置在 tomcat-juli.jar之前, 那么估计jdk/jre下默认的logger实现将接管日志打印,因此logging.properties中的配置就失效了,因此也产生不出localhost等文件了



11月 172015
 

启用tomcat的压缩,效果不错。

 

当网站从服器端请求的数据较大时,在有限的带宽下就会造成浏览器加载缓慢,有时候会造成页面没有响应,使用户体验变得很差,tomcat为我们提供了有效的解决了办法,就是使用压缩来解决传输问题。

        tomcat使用HTTP/1.1 GZIP 来压缩,以减少带宽压力,
       首先介绍下gzip:
        HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来.一般对纯文本内容可压缩到原大小的40%.这样传输就快了,效果就是你点击网址后会很快的显示出来.当然这也会增加服务器的负载. 一般服务器中都安装有这个功能模块的.
      我们使用简单的例子来介绍tomcat的压缩使用:(使用firebug查看请求情况)

 首先是一个简单的servlet:
内容:

public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType(“text/html”);
        PrintWriter out = response.getWriter();
        out
                .println(“<!DOCTYPE HTML PUBLIC \”-//W3C//DTD HTML 4.01 Transitional//EN\”>”);
        out.println(“<HTML>”);
        out.println(”  <HEAD><TITLE>A Servlet</TITLE></HEAD>”);
        out.println(”  <BODY>”);
        out.print(” <select> “);
        for (int i = 0; i < 100000; i++) {
            out.print(“<option>testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest”+i+”</option>”);
        }

        out.println(“</select>”);
        out.println(”  </BODY>”);
        out.println(“</HTML>”);
        out.flush();
        out.close();
    }

我们将输出一个十万个选项的下拉框,在不使用的压缩的时候:

    请求数据达到9m ,大概的计算下我的下载用时(4m长城宽带):9*1024/(4*1024/8)=18m  ,加上多人共享带宽,也就是差不多20m。firebug显示20.96。

    这个速度网站体验肯定是很差的,接下来使用tomcat的压缩以后看看:

   当然是要对其进行配置:
   有以下几个参数可以使用:

    compression=”on” 
是否启用压缩 on为启用(文本数据压缩) off为不启用, force 压缩所有数据
compressionMinSize1=”2048″ 
当超过最小数据大小才进行压缩
 noCompressionUserAgents=”gozilla, traviata” 
哪些客户端发出的请求不压缩,默认是不限制
compressableMimeType=”text/html,text/xml,text/javascript,text/css,text/plain”
配置想压缩的数据类型,默认是 text/html,text/xml,text/plain

配置以后是这样的:

<Connector port=”8088″ protocol=”HTTP/1.1″ 
               connectionTimeout=”20000″ 
               redirectPort=”8443″
               compression=”on” 
               compressionMinSize1=”2048″ 
               noCompressionUserAgents=”gozilla, traviata” 
               compressableMimeType=”text/html,text/xml,text/javascript,text/css,text/plain”/>

启动后再看:

 

这次数据被压缩到274.7k,响应速度也减少了一半,当然,服务器的数据压缩和浏览器的数据解压都需要使用时间。


详细的compression配置可参考tomcat 官网:http://tomcat.apache.org/tomcat-7.0-doc/config/http.html


转自:http://www.blogjava.net/freeman1984/archive/2010/09/15/332121.html

1月 212015
 

虽然是英文的资料,但应该都能看懂, 介绍了使用注解和程序方式编写websock。 对于理解tomcat下websock sample会很有帮助

JSR 356 defines Java API for WebSocket 1.0. It defines a standard-based programming model for creating WebSocket client and server endpoint. Both kind of endpoints can be created programmatically or using annotations. This Tip OfThe Day (TOTD) provide short snippets of how to write a WebSocket client and server endpoint programmatically or using annotations.

The complete source code in this sample can be downloaded from here.

Lets start with annotation-based server endpoint.

@ServerEndpoint(“/websocket”)
public class MyEndpoint {
    
  @OnMessage
  public String echoText(String name) {
    return name;
  }
}

@ServerEndpoint marks the POJO as a WebSocket server endpoint. URI of the deployed endpoint is as valueattribute of the annotation.  echoText method is invoked whenever a message with text payload is received by this endpoint. Payload of the message is mapped to the parameter name. A synchronous response is returned to the client using the return value.

Programmatic server endpoint can be defined as:

public class MyEndpoint extends Endpoint {

  @Override
  public void onOpen(final Session session, EndpointConfig ec) {
    session.addMessageHandler(new MessageHandler.Whole<String>() {

      @Override
      public void onMessage(String text) {
        try {
          session.getBasicRemote().sendText(text);
        } catch (IOException ex) {
          Logger.getLogger(MyEndpoint.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
  });
}

A programmatic server endpoint is defined by extending Endpoint abstract class. onOpen method is overridden to be notified of when a new conversation has started. Session captures the other end of the conversation.EndpointConfig identifies the configuration object used to configure this endpoint. Multiple MessageHandlers are registered to handle text, binary, and pong messages. The first parameter of onOpen captures the other end of the conversation. A synchronous response to the client is sent by calling getBasicRemote().sendText(…) method.

Programmatic server endpoint needs to be configured using ServerApplicationConfig.

public class MyApplicationConfig implements ServerApplicationConfig {

  @Override
  public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> set) {
    return new HashSet<ServerEndpointConfig>() {
      {
        add(ServerEndpointConfig.Builder
            .create(MyEndpoint.class, “/websocket”)
            .build());
      }
    };
  }

  @Override
  public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> set) {
    return Collections.emptySet();
  }
}

WebSocket runtime scans the WAR file with all implementations of ServerApplicationConfig and registers the endpoint returned from getEndpointConfigs and getAnnotatedEndpointClasses. The URI of the server endpoint is published using ServerEndpointConfig.Builder.

Now lets take a look at annotated client endpoint.

@ClientEndpoint
public class MyClient {
  @OnOpen
  public void onOpen(Session session) {
    try {
      String name = “Duke”;
      System.out.println(“Sending message to endpoint: ” + name);
      session.getBasicRemote().sendText(name);
    } catch (IOException ex) {
      Logger.getLogger(MyClient.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
}

@ClientEndpoint marks the POJO as a WebSocket client endpoint. onOpen method is invoked whenever a new WebSocket connection is opened and is identified by @OnOpen annotation. Session captures the other end of the conversation. A synchronous message is sent to the server using session.getBasicRemote.sendText() method.

This client can connect to the endpoint as:

WebSocketContainer container = ContainerProvider.getWebSocketContainer();
String uri = “ws://localhost:8080” + request.getContextPath() + “/websocket”;
container.connectToServer(MyClient.class, URI.create(uri));

And finally programmatic client endpoint.

public class MyClient extends Endpoint {
  @Override
  public void onOpen(final Session session, EndpointConfig ec) {
    session.addMessageHandler(new MessageHandler.Whole<String>() {

      @Override
      public void onMessage(String text) {
        System.out.println(“Received response in client from endpoint: ” + text);
      }
  });
  try {
    String name = “Duke”;
      System.out.println(“Sending message from client -> endpoint: ” + name);
      session.getBasicRemote().sendText(name);
    } catch (IOException ex) {
      Logger.getLogger(MyClient.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
}

The first parameter of onOpen captures the other end of the conversation.  EndpointConfig identifies the configuration object used to configure this endpoint. Multiple MessageHandlers are registered to handle text, binary, and pong messages. onMessage method is called whenever a message is received from the endpoint. A synchronous request to the server is sent by calling getBasicRemote().sendText(…) method.

This client can connect to the endpoint as:

WebSocketContainer container = ContainerProvider.getWebSocketContainer();
String uri = “ws://localhost:8080” + request.getContextPath() + “/websocket”;
container.connectToServer(MyClient.class, 
                null,
                URI.create(uri));

Now go download your GlassFish b82samples source code, and run them.

3月 142014
 

A:

1.在eclipse的run configurations中创建一个maven build,选择好Maven工程,在Goals一栏中输入jetty:run。然后进入“jre”Tab,在vm arguments一栏中输入-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

2.打开debug configuration,创建一个remote java application,在host中输入服务器地址,一般就本机localhost。在port一栏中输入上面配置中端口号8000。这样,当服务器启动后,就可以进行远程debug了。这种debug方式的好外是可以在debug依赖的jar包,并在上面设置断点。(前提是你已经获得了jar包的源代码)

 

B:

如果是Tomcat,只需要在tomcat/bin/的catalina.bat文件的开头加入下面的设置即可:

SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000

然后在eclipse新建一个remote debug,端口填入8000即可。

9月 222013
 

1.  401错误

[ERROR] Failed to execute goal  org.codehaus.mojo:tomcat-maven-plugin:1.1:deploy(default-cli) on project  my_struts: Cannot invoke Tomcat manager: Server returned HTTP response code: 401  for URL: http://localhost:8080/manager/deploy?path=%2Fmyproject&war= ->  [Help 1]

2. 403错误

 maven 403 No server username specified – using default  Cannot invoke Tomcat manager: Server rened HTTP response code: 403 for URL

 

[ERROR] Failed to execute goal org.codehaus.mojo:tomcat-maven-plugin:1.1:deploy(default-cli) on project my_struts: Cannot invoke Tomcat manager: Server returned HTTP response code: 403 for URL: http://localhost:8080/manager/deploy?path=%2Fmyprojcet&war=

 

解决方法:

1. 打开tomcat下的tomcat-users.xml文件,添加类似下面的语句:

<?xml version='1.0' encoding='utf-8'?> 
   
<tomcat-users> 
   
  <role rolename="manager"/> 
   
  <role rolename="manager-script"/> 
   
  <role rolename="admin-gui"/> 
   
  <role rolename="manager-gui"/>   
   
  <user username="admin" password="admin" roles="manager,manager-gui,admin-gui,manager-script"/> 
   
</tomcat-users>
 

2. 修改本机maven的配置文件setting.xml (linux默认路径为:/home/当前用户/.m/setting.xml),添加下面的server: 

<servers>

  <server>  

       <id>tomcat</id>  

       <username>admin</username>  

       <password>admin</password>  

  </server>     

</servers>

 3. 修改出错项目(401,403错误)的pom.xml文件

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>tomcat-maven-plugin</artifactId>

<version>1.1</version>

<configuration>

<server>tomcat</server><!– 这个server标签里面的值(tomcat)要和你的setting.xml里面的id的值(tomcat)一致–>

 

<username>admin</username>

<password>admin</password>

<!– Tomcat 7.x –>

<url>http://localhost:8080/manager/text</url>

 

<!– Tomcat 6.x 

<url>http://localhost:8080/manager</url>  // 此处千万别加/html,如果写了就会出现403错误

–>

<path>/myproject</path>

</configuration>

</plugin>

 

摘自:http://hi.baidu.com/ae6623/item/809c7cfb3f9eae4d922af272

理解Tomcat的Classpath-常见问题以及如何解决(转)

 java, tomcat  理解Tomcat的Classpath-常见问题以及如何解决(转)已关闭评论
2月 282013
 

转自: http://www.linuxidc.com/Linux/2011-08/41684.htm

在很多Apache Tomcat用户论坛,一个问题经常被提出,那就是如何配置Tomcat的classpath,使得一个web应用程序能够找到类或者jar文件,从而可以正常工作。就像许多困扰Tomcat新用户的问题一样,这个问题也很容易解决。在这篇文章中,我们将会介绍Tomcat是如何产生和利用classpath的,然后一个一个解决大多数常见的与classpath相关的问题。

为什么Classpaths给Tomcat用户带来了麻烦

一个classpath就是一个参数,来告诉java虚拟机在哪里可以找到类和包去运行一个程序。classpath总是在程序源码外设置的,将其同程序分开可以允许java代码以一种抽象的方式来引用类和包,允许程序可以在任何系统上被配置。为什么那些很有经验的java用户,他们已经非常清楚classpath是什么了,但是在Tomcat运行程序的时候,还是会遇到这样那样的问题呢?
可能有以下三个原因:
1、Tomcat处理classpaths的方式与其他java程序是不同的
2、Tomcat的版本不同,其处理classpaths的方式也可能不同
3、Tomcat的文档和默认的配置要求以一种特定的方式来完成某些事情。如果你不遵循这种方式,那么你就会陷入麻烦之中。关于如何解决常见的classpath问题,没有信息可以提供,比如外部依赖,共享依赖或者多版本的相同依赖。
Tomcat的Classpath如何不同于标准的Classpath

Apache Tomcat目的是尽可能的独立,直观和自动化,为了有效的管理,标准化web应用程序的配置和部署过程,为了安全和命名控件的考虑,限制对不同库的访问。这就是为什么不使用java classpath环境变量的原因了,java的classpath是声明依赖类库默认的地方,Tomcat的start脚本忽略了这个变量,在创建Tomcat系统classloader的时候产生了自己的classpaths。
想要理解Tomcat如何处理classpath的,看看以下Tomcat6的启动过程:
1、java虚拟机的bootstrap loader加载java的核心类库。java虚拟机使用JAVA_HOME环境变量来定位核心库的位置。
2、Startup.sh,使用start参数调用Catalina.sh,重写系统的classpath并加载bootstrap.jar和tomcat-juli.jar。这些资源仅对Tomcat可见。
3、为每一个部署的Context创建Class loader,加载位于每个web应用程序WEB-INF/classes和WEB-INF/lib目录下的所有类和jar文件。每个web应用程序仅仅可见自己目录下的资源。
4、Common class loader加载位于$CATALINA_HOME/lib目录下的所有类和jar文件,这些资源对所有应用程序和Tomcat可见。
Tomcat的类加载机制是如何在不同版本之间变化的
之前的Tomcat版本,其类加载机制有一些不同

Tomcat 4.x以及更早的版本,一个server loader负责加载Catalina类,现在由commons loader负责了。
Tomcat 5.x,一个shared loader负责加载在应用程序间共享的类,这些类位于$CATALINA_HOME/shared/lib。在Tomcat6中,这种方式被取消了。
Tomcat 5.x也包括了一个Catalina loader,加载所有的Catalina组件,现在也被Common loader取代了。
当你不能按照Tomcat要求的方式做事的时候,怎么办

如果你使用Tomcat文档推荐的方式做事,你不应该有关于classpath的问题。你的wars包含了所有库和包的复本,你没有任何理由去在多个应用程序间共享一个jar文件,你不需要调用任何外在的资源,你也将不会遇到复杂的情况,例如一个web应用程序运行的时候需要一个jar文件的多个版本。但是如果你确实不能按照推荐的方式来做的时候,一个文件可以解决你所有的问题:catalina.properties。
使用catalina.properties来配置Tomcat Classpath

对于那些不想使用默认来加载方式的用户来说,幸运的是,Tomcat的classpath选项不是硬编码的,它们是从$CATALINA_HOME/conf/catalina.properties文件中读取的。
这个文件包含了除bootstrap和system loader之外的所有其他的loaders,检查这个文件,你会有一些新发现:
1、Server以及Shared loader还没有被删除,如果它们的属性没有定义,Commons loader负责处理。
2、被各种loaders加载的类和jar文件不会被自动加载,它们只是用一个简单的通配符语法指定为一组。
3、这里没有说你不能指定一个额外的仓库,事实上就是说你是可以的。
server loader不应该改动,但是shared loader还是有许多有用的应用。(shared loader将会在启动过程的最后阶段加载它的类,在Commons loader之后)。现在让我们看看一些常见的问题以及如何解决。
问题、解决方案和最佳实践

问题:我的应用程序依赖一个外部的仓库,我不能引用它。
让Tomcat知道一个外部的仓库,在catalina.properties文件的shared loader位置,使用正确的语法,声明这个仓库。语法基于你要配置的文件或仓库的类型:
1、增加一个文件夹作为类仓库,使用“path/to/foldername”
2、增加一个文件夹下的所有jar文件作为类仓库,使用”path/to/foldername/*.jar”
3、增加单个jar文件作为类仓库,使用”file://path/to/foldername/jarname.jar”
4、调用环境变量,使用${}格式,例如${VARIABLE_NAME}
5、声明多个资源,用逗号分隔开
6、所有的路径相对于CATALINA_BASE或CATALINA_HOME,或者是绝对路径
问题:我想多个应用程序共享一个jar文件,这个jar文件在Tomcat里面。
除了一些常见的第三方库(比如JDBC drivers),最好不要在$CATALINA_HOME/lib目录下包含额外的库,即使这样在一些情况下是可行的。应该重新创建比如/shared/lib和/shared/classes目录,然后在catalina.properties配置shared.loader属性:
“shared/classes,shared/lib/*.jar”
问题:除了另一个框架,我在一个应用中使用了一个嵌入式Tomcat server,当我访问框架组件的时候遇到classpath errors。
这个问题好像超出了这篇文章的范畴,但是作为一个常见的classpath相关的问题,这里对如何引起你的错误作一个简单的介绍。
当嵌入到包含另外核心框架(Wicket或者Spring)的应用中时,Tomcat将在启动框架的时候,使用System classloader加载核心类,而不是从应用的WEB-INF/lib目录下加载。
java的类加载是懒加载,就是说请求某个类的第一个加载器拥有这个类剩下的生命周期。如果System classloader,它的类对web应用是不可见的,首先加载了框架相关的类,java虚拟机将会阻止来的其他实例被创建,这样就引起了classpath错误。
解决这个问题的一种方式就是增加一个自定义的bootstrap classloader,使得这个classloader加载合适的库,然后对程序剩下部分的启动正常对待。
问题:我使用一个标准的应用程序,程序的war包含了依赖的所有包,但是我仍然遇到类定义错误。
这个问题可能是由许多事情引起的,包括编译或部署过程不是很正确,但是最有可能是web应用程序的目录结构不对造成的。
java命名转换要求类名映射到存放这个类的目录结构。例如,一个类com.mycompany.mygreat.class需要被存放到目录WEB-INF/classes/com/mycompany/。
经常代码中丢失一个点号就会引起classpath相关的问题。
问题:我的web应用程序的不同模块需要使用同一个jar包的两个不同版本。
这种情况常常出现在一个应用程序中使用多个web框架,这些web框架依赖一个库的不同版本。
有几种解决方案,但是它们都和classpath不相关。我们在这里说这个问题,是因为一些用户试图在框架的jar文件中的Manifest文件中指定依赖的库的不同版本的classpath,来解决这个问题。
这种方式在一些web应用服务器中是支持的,所以一些用户想要在Tomcat中也使用这种方式。但是在Manifest文件中指定classpath在Tomcat中是不支持的,这也不是Servlet说明的一部分。
有以下四种方式来解决这个问题:
1、你可以更新框架的版本,如果这里能够使得与其他框架依赖相同的版本。
2、你可以创建两个或更多的自定义classloaders,每个jar文件一个,在WEB/INF/context.xml文件中配置,创建你所需要的两个不同版本的类的实例。
3、你可以使用jarjar工具将框架和它依赖的库打包成一个jar文件,那么它们会一起被加载。
4、如果你发现你每隔一天就要处理这种情况,你应该考虑使用OSGI框架,这个框架有许多方法专门就是用来处理这种一个类的多个版本需要运行在同一个java虚拟机里的情况的。
最佳实践
1、避免在Tomcat里使用Commons loader加载不属于Tomcat标准发布的库和包,这可能会引起兼容错误。如果你需要在多个应用程序间共享一个库或包,创建shared/lib和shared/classes目录,然后配置到catalina.properties文件的Shared loader。
2、以上规则的一个例外就是常用的第三方共享库,例如JDBC driver。这些应该放到$CATALINA_HOME/lib目录下。
3、可能的话,尽可能按照Tomcat的开发者推荐的方式使用Tomcat,如果你发现你不得不频繁配置classpath,你可能需要重新考虑你的开发过程了。