blogjava-凯发k8网页登录http://www.blogjava.net/wangxinsh55/category/24824.htmlzh-cnmon, 18 jul 2016 08:51:56 gmtmon, 18 jul 2016 08:51:56 gmt60 使用embeded tomcat进行嵌入式javaee开发-启动tomcathttp://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.htmlsimonesimonemon, 18 jul 2016 06:42:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.htmlhttp://www.blogjava.net/wangxinsh55/comments/431229.htmlhttp://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.html#feedback0http://www.blogjava.net/wangxinsh55/comments/commentrss/431229.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/431229.htmlhttps://www.iflym.com/index.php/code/use-embeded-tomcat-to-javaee-start-tomcat.html
昨天在网上研究了下关于将tomcat嵌入到主程序中进行运行,而不是像以前将一个web项目copy到tomcat中进行运行。之所以这样做的原 因,即是因为项目部署到客户方,在进行更新的时候,需要手动地进行更新,再把相应代码copy到tomcat,然后再运行。运用embeded tomcat就可以将项目与tomcat分开,在进行更新时,先使用自定义的程序进行自动化更新,待更新完毕之后,再启动tomcat(或其它 javaee容器)进行项目运行。

     这样做的最终效果就是修改了项目的运行方式。原先的运行方式是以tomcat为中心,由tomcat来启动和终止项目,现在是由我们的启动程序 为中心,由启动程序来负责启动和终止项目。就相当于现在流行的cs程序一样,有单独的启动脚本,在启动时进行环境预初始化,更新程序以及其它操作,待完成 之后再进行最终的项目启动。

     这篇主要讲解如何使用embeded tomcat在代码中进行启动和终止。网上的一般文章均为tomca5.x来做,这里使用了最新的tomcat7,因为tomcat7为embeded开 发,单独发布了org.apache.tomcat.embed包,以进行独立的embed开发。以下是相应的maven包

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<dependency>
            <groupid>org.apache.tomcat.embedgroupid>
            <artifactid>tomcat-embed-coreartifactid>
            <version>7.0.2version>
        dependency>
        <dependency>
            <groupid>org.apache.tomcatgroupid>
            <artifactid>tomcat-utilartifactid>
            <version>7.0.2version>
        dependency>
        <dependency>
            <groupid>org.apache.tomcat.embedgroupid>
            <artifactid>tomcat-embed-jasperartifactid>
            <version>7.0.2version>
        dependency>
        <dependency>
            <groupid>org.apache.tomcat.embedgroupid>
            <artifactid>tomcat-embed-logging-juliartifactid>
            <version>7.0.2version>
        dependency>

    使用了embed包中的core包,以及用于编译jsp的jasper包,然后是工具类以及进行上场记录的logging-juli包。开始写代码:

1
2
3
4
5
6
7
//设置工作目录
        string catalina_home = "d:/";
        tomcat tomcat = new tomcat();
        tomcat.sethostname("localhost");
        tomcat.setport(startport);
        //设置工作目录,其实没什么用,tomcat需要使用这个目录进行写一些东西
        tomcat.setbasedir(catalina_home);

    上面使用了tomcat类来进行启动类,在tomcat7以前均是使用一个叫embed类来进行启动,在tomcat7之后,embed类被不建 议使用,而建议使用新的tomcat类来进行启动了。然后设置主机名,端口,再设置一个工作目录。这个工作目录可以是任意目录,主要是tomcat需要这 个目录来记录一些东西,比如记录word信息,日志信息(如果配置了日志的话),以及临时文件存储等。

1
2
3
4
5
6
7
8
//设置程序的目录信息
        tomcat.gethost().setappbase("e:/");
        // add aprlifecyclelistener
        standardserver server = (standardserver) tomcat.getserver();
        aprlifecyclelistener listener = new aprlifecyclelistener();
        server.addlifecyclelistener(listener);
        //注册关闭端口以进行关闭
        tomcat.getserver().setport(shutdownport);

    上面的代码,首先设置我们的项目程序所在的appbase,即放项目代码的地方。在通常的tomcat配置中,这个目录一般是webapps。接 着设置一个listener,这个listener主要是负责启动一些比如html native支持程序以及ipv6等信息配置(可以忽略)。接着是配置一个关闭的注册端口,当向这个端口发送信息时,就可以达到关闭tomcat的目的 (后面会讲)。

1
2
3
4
5
6
7
8
9
//加载上下文
        standardcontext standardcontext = new standardcontext();
        standardcontext.setpath("/aa");//contextpath
        standardcontext.setdocbase("aa");//文件目录位置
        standardcontext.addlifecyclelistener(new tomcat.defaultwebxmllistener());
        //保证已经配置好了。
        standardcontext.addlifecyclelistener(new tomcat.fixcontextlistener());
        standardcontext.setsessioncookiename("t-session");
        tomcat.gethost().addchild(standardcontext);

    我们单独使用了一个context来为这个host添加上下文,tomcat本身提供一个方法tomcat.addweb方法来添加项目包,不过 由于这里需要单独设置一个tomcat的sessionname,所以使用与与tomcat.addweb实现类似的方法来添加一个项目包。
    以上代码中有两个需要注意的listener,一个是defaultwebxmllistener,这个是由tomcat加载一些默认的配置信 息,比如jspservlet,以及一些繁复的mime/type信息;加上这个,就不需要我们自己去写这么多的配置,因为每个项目都需要这些。这个配置 与tomcat目录下的conf/web.xml中的配置一样,只不过这里是代码化了。第二个是fixcontextlistener,这个主要是在项目 部署完后,将这个上下文设置为configured,表示已经配置好了(不然,tomcat启动时会报错,即相应上下文还未配置好)。
    配置ok了之后,就是启动tomcat了:

1
2
tomcat.start();
        tomcat.getserver().await();

    启动tomcat,并让tomcat在关闭端口上监听。如果没有最后一句,程序将直接结束,保证监听之后,tomcat将一直监听关闭事件,待有关闭事件之后才结束当前程序。所以如果想要关闭当前的tomcat,只需要向关闭端口发送一些信息即可:

1
2
3
4
5
6
7
8
9
private static void shutdown() throws exception {
        socket socket = new socket("localhost", shutdownport);
        outputstream stream = socket.getoutputstream();
        for(int i = 0;i < shutdown.length();i )
            stream.write(shutdown.charat(i));
        stream.flush();
        stream.close();
        socket.close();
    }

    这样即可达到关闭tomcat的目的。

     实际上看整个项目代码,项目代码的运行,就是一个配置一个基础的server.xml(即tomcat目录下的 conf/server.xml),先配置运行端口,关闭监听端口;然后配置运行的host以及添加一个上下文context,最后就开始运行并开始监 听。对照这个程序,再看一下server.xml中的配置信息,就很容易明白以上这段代码了。



simone 2016-07-18 14:42 发表评论
]]>
tomcat7升级至tomcat8后兼容性问题修改http://www.blogjava.net/wangxinsh55/archive/2015/04/09/424255.htmlsimonesimonethu, 09 apr 2015 09:35:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2015/04/09/424255.htmlhttp://www.blogjava.net/wangxinsh55/comments/424255.htmlhttp://www.blogjava.net/wangxinsh55/archive/2015/04/09/424255.html#feedback0http://www.blogjava.net/wangxinsh55/comments/commentrss/424255.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/424255.html另外tomcat8对写入cookie的字符串限制更严格,不允许使用/ 这样导致无法写cookie的path路径。

目前发现能解决的办法有两种
方案一、
server.xml文件connector结点添加 uriencoding="iso-8859-1" 属性


方案二、
catalina.properties配置添加配置属性
#设置为true则默认使用iso-8859-1编码,否则默认是utf-8编码,参考tomcat文档
#http://tomcat.apache.org/tomcat-8.0-doc/config/http.html  uriencoding 属性部分
#http://tomcat.apache.org/tomcat-8.0-doc/config/systemprops.html   org.apache.catalina. strict_servlet_compliance 属性部分
org.apache.catalina.strict_servlet_compliance=true

#cookie的path限制修改,false允许使用/ 参考tomcat文档
#http://tomcat.apache.org/tomcat-8.0-doc/config/systemprops.html
org.apache.tomcat.util.http.servercookie.fwd_slash_is_separator=false


simone 2015-04-09 17:35
]]>
tomcat的reloadable参数的意思http://www.blogjava.net/wangxinsh55/archive/2011/05/31/351449.htmlsimonesimonetue, 31 may 2011 08:55:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2011/05/31/351449.htmlhttp://www.blogjava.net/wangxinsh55/comments/351449.htmlhttp://www.blogjava.net/wangxinsh55/archive/2011/05/31/351449.html#feedback0http://www.blogjava.net/wangxinsh55/comments/commentrss/351449.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/351449.html 开启了tomcat的reloadable=true,那么每当相关文件改变时,tomcat会停止web app并释放内存,然后重新加载web app.这实在是个浩大的工程。
       另外网上有一篇文章是关于在tomcat运行动态重载类,下面是该文章的内容
        
  1. 为什么写这篇文档?

使 用过hibernate, spring或其他大型组件,写过50个类以上的网络应用程序(web application)的开发者应该知道,当系统中有很多类时,如果开启了tomcat的reloadable=true,那么每当相关文件改变 时,tomcat会停止web app并释放内存,然后重新加载web app.这实在是个浩大的工程。

所以我总是在想如果能有只重载某几个类的功能,将极大的满足我这个即时调试狂。

去年我在论坛上发帖,才发现已经有一些应用服务器具有了这个功能,比如weblogic, websphere, 等等。好像还有一个很酷的名字,叫开发模式。看来我还是孤陋寡闻了点。

当然很多人都是在tomcat上开发,包括我。我很喜欢它的轻小,那些大内存和高cpu消耗的应用服务器不愧为硬件杀手,没理由不改进tomcat :)。

  1. 最终实现功能

我没有时间去研究tomcat的文件监听机制,也没时间去把他写成”开发模式”这么完整的功能,我最终实现的是,实现重载功能的测试jsp--很抱歉我还是没办法写得更完整。当然,你可以在这个基础上进行改进。

  1. 阅读须知

阅读本文,你应该具备以下知识

    1. jvm 规范有关类加载器的章节

    2. tomcat 类加载机制

    3. java 反射机制

    4. ant

      (好象该网址被不定时封锁,有时能上,有时不能)

最好在你的电脑上安装ant,因为tomcat源码包使用ant从互联网获得依赖包。不过我也是修改了一个错误才使它完全编译通过。

当然,你也可以用其他ide工具检查并添加依赖包,在ide中,其实你只需要添加jar直到使org.apache.catalina.loader.webappclassloader无错即可。

  1. 修改过程

    1. 说明

新添加的代码请添加到java文件的末尾,因为我在说明行数的时候,尽量符合原始行数

    1. web app类加载器

在tomcat中,org.apache.catalina.loader.webappclassloader是web app的类加载器,所以需要修改它实现重载功能。

    1. 资源列表

在webappclassloader中,有一个map类型属性resourceentries,它记载了web app中web-inf/classes目录下所加载的类,因此当我们需要重载一个类时,我们需要先将它在resourceentries里删除,我编写了一个方法方便调用:

public boolean removeresourceentry(string name) {

     if (resourceentries.containskey(name)) {

         resourceentries.remove(name);

         return true;

     }

     return false;

}

    1. 是否重载标志

让webappclassloader需要知道加载一个类是否使用重载的方式。所以我建立一个boolean 类型的属性和实现它的getter/setter方法:

private boolean isreload = false;


      public boolean isreload() {

          return isreload;

      }


      public void setreload(boolean isreload) {

          this.isreload = isreload;

      }

    1. 动态类加载器

根据jvm类加载器规范,一个类加载器对象只能加载一个类1次,所以重载实际上是创建出另一个类加载器对象来加载同一个类。当然,我们不需要再创建一个webappclassloader,他太大而且加载规则很复杂,不是我们想要的,所以我们创建一个简单的类加载器类org.apache.catalina.loader.dynamicclassloader:

package org.apache.catalina.loader;


import java.net.url;

import java.net.urlclassloader;

import java.security.codesource;

import java.util.*;


/**

* 动态类加载器

*

@author peter

*

*/

public class dynamicclassloader extends urlclassloader {

    /* 父类加载器 */

    private classloader parent = null;


    /* 已加载类名列表 */

    private list classnames = null;


    /**

    * 构造器

    *

    * @param parent

    * 父类加载器,这里传入的是webappclassloader

    */

    public dynamicclassloader(classloader parent) {

        super(new url[0]);

        classnames = new arraylist();

        this.parent = parent;

    }


    /**

    * 从类的二进制数据中加载类.

    *

    * @param name

    * 类名

    * @param classdata

    * 类的二进制数据

    * @param codesource

    * 数据来源

    * @return 成功加载的类

    * @throws classnotfoundexception

    * 加载失败抛出未找到此类异常

    */

    public class loadclass(string name, byte[] classdata, codesource codesource) throws classnotfoundexception {

        if (classnames.contains(name)) {

            // system.out.println("此类已存在,调用 loadclass 方法加载.");

            return loadclass(name);

        } else {

            // system.out.println("新类, 记录到类名列表,并用类定义方法加载类");

            classnames.add(name);

            return defineclass(name, classdata, 0, classdata.length, codesource);

        }

    }


    /* *

    * 重载此方法,当要加载的类不在类名列表中时,调用父类加载器方法加载.

    * @see java.lang.classloader#loadclass(java.lang.string)

    */

    public class loadclass(string name) throws classnotfoundexception {

        if (!classnames.contains(name)) {

            //system.out.println("不在类名列表中,调用父类加载器方法加载");

            return parent.loadclass(name);

        }

        return super.loadclass(name);

    }

}

    1. 在webappclassloader中添加dynamicclassloader

      1. 添加属性

private dynamicclassloader dynamicclassloader = new dynamicclassloader(this);

      1. 添加重建方法,以便需要再次重载时替换掉上次的类加载器对象

public void recreatedynamicclassloader() {

                dynamicclassloader = new dynamicclassloader(this);

            }

    1. 修改调用点

      1. 第832行,公开findclass方法

public class findclass(string name) throws classnotfoundexception {

      1. 第1569行,添加如下一行代码。

if (isreload) removeresourceentry(name);

      1. 第1577行,这里好像是一个bug,具体原因我忘了-_-||

if ((entry == null) || (entry.binarycontent == null))

改为

if ((entry == null) || (entry.loadedclass == null && entry.binarycontent == null))

      1. 第1633~1636行

if (entry.loadedclass == null) {

                clazz = defineclass(name, entry.binarycontent, 0, entry.binarycontent.length,

                    codesource);

            改为

            byte[] classdata = new byte[entry.binarycontent.length];

            system.arraycopy(entry.binarycontent, 0, classdata, 0,

            classdata.length);

            if (entry.loadedclass == null) {

                clazz = isreload ?

                    dynamicclassloader.loadclass(name,

                    classdata, codesource) :

                    defineclass(name,

                    classdata, 0, classdata.length, codesource);

    1. 测试代码

      1. test.jsp

我测试用的jsp为$catalina_home/webapps/root/test.jsp,由于webapp里面并不会显式加载tomcat的核心类,所以我们需要用反射代码调用webappclassloader的方法。代码如下:

<%

classloader loader = (thread.currentthread().getcontextclassloader());

class clazz = loader.getclass();

java.lang.reflect.method setreload = clazz.getmethod("setreload", new class[]{boolean.class});

java.lang.reflect.method recreate = clazz.getmethod("recreatedynamicclassloader", null);

java.lang.reflect.method findclass = clazz.getmethod("findclass", new class[]{string.class});

recreate.invoke(loader, null);

setreload.invoke(loader, new object[]{true});

class a = (class)findclass.invoke(loader, new object[]{"org.aclass"});

setreload.invoke(loader, new object[]{false});

a.newinstance();

// 如果你使用下面这行代码,当重编译类时,请稍微修改一下调用它的jsp,让jsp也重新编译

//org.aclass a = (org.aclass)a.newinstance();

// 下面这些代码是测试当一个类不在dynamicclassloader类名列表时的反应

//a.test();

//java.lang.reflect.method test = a.getclass().getmethod("test", null);

//test.invoke(a, null);

%>

      1. org.aclass

package org;


        public class aclass {

            public aclass() {

                // 修改输出内容确认tomcat重新加载了类

                system.out.println("aclass v3");

            }


            public void createbclass() {

                new bclass();

            }

        }

      1. org.bclass

package org;


        public class bclass {

            public bclass() {

                //修改输出内容确认tomcat重新加载了类

                system.out.println("bclass v1");

            }

        }

    1. 测试步骤

      1. 按照上述步骤修改tomcat源码并编译。

      2. 用winzip/winrar/file-roller打开$catalina_home/server/lib/catalina.jar。把前面编译完成后的org.apache.catalina.loader目录下的class文件覆盖jar中同名文件。

      3. 编译org.aclass和org.bclass

      4. 启动tomcat并在浏览器中打开测试页http://localhost:8080/test.jsp

      5. 修改org.aclass中的system.out.println();语句并重编译类。

      6. 按下f5按键刷新浏览器。

      7. 查看tomcat控制台是否输出了不同的语句?

      8. good luck! :)))



simone 2011-05-31 16:55
]]>
tomcat定时重启与服务注册方法 http://www.blogjava.net/wangxinsh55/archive/2010/01/27/310929.htmlsimonesimonewed, 27 jan 2010 05:15:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2010/01/27/310929.htmlhttp://www.blogjava.net/wangxinsh55/comments/310929.htmlhttp://www.blogjava.net/wangxinsh55/archive/2010/01/27/310929.html#feedback0http://www.blogjava.net/wangxinsh55/comments/commentrss/310929.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/310929.html保存以下脚本成tomcat.bat,计划任务指定每天4点执行该脚本
@echo off
net stop tomcat5
rem ping 20个包,实现延时功能
ping 127.0.0.1 -n 20
net start tomcat5
 
 
注意这里的tomcat5是tomcat在windows的服务名,注册服务的方法如下:
找到tomcat安装目录bin子目录下的service.bat
在命令行里执行:
service.bat install
则自动安装服务。
定时重启sql server
net stop mssqlserver
net start mssqlserver
tomcat产生垃圾缓存文件的处理与tomcat的定时重启

由于程序中使用了jtds驱动来连接数据库。
一段时间后,我发现tomcat的temp文件夹内jtds*.tmp文件(形如jtds424647.tmp)越来越多,容量也越来越大。有一次清理时,据然有几个g多,严重的影响了系统的运行速度。

解决措施:

如果是linux系统
可以指定启动时-djava.io.tmpdir=/tmp
这个目录系统会用cron脚本自动清理文件

如果是windows,需要定期清理tomcat的tmp文件

可以用windows自带的定时任务器建立如下deltmp.bat的文件

@echo off

 

:start

::启动过程,切换目录

set pwd=�%

cd %1

echo 工作目录是:& chdir

 

:clean

::主处理过程,执行清理工作

@echo on

rem @for  /r %%c in (.log) do @if exist %%c ( rd /s /q %%c & echo     删除目录%%c)

@echo off

@del logs\*.log

@del temp\*.tmp

del /f /s /q e:\osaplatform\web-inf\logs\*.log.*-*

echo "当前目录下的log信息已清除"

goto end

 

:noclean

::分支过程,取消清理工作

echo "log信息清楚操作已取消"

goto end

 

:end

::退出程序

cd "%pwd%"

rem pause

 

 

tomcat由于运行的时间过长造成内存不宜释放,导致运行性能的降低,定时重启tomcat有利于提升系统的性能,

首先建立如下的bat文件

set java_home=c:\program files\java\jdk1.6.0_06

e:\tomcat6_hb\bin\service.bat install tomcat604

注册为windows服务

然后在建立tomcat.bat,并将此文件放到windows定期任务中

@echo off

net stop tomcat5

rem ping 20个包,实现延时功能

ping 127.0.0.1 -n 20

net start tomcat5

如果需要解除服务,则建立如下文件,直接执行即可

set java_home=c:\program files\java\jdk1.6.0_06

e:\tomcat6_hb\bin\service.bat remove tomcat604



simone 2010-01-27 13:15
]]>
解决tomcat下context重复启动(转)http://www.blogjava.net/wangxinsh55/archive/2009/03/11/259229.htmlsimonesimonewed, 11 mar 2009 14:09:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2009/03/11/259229.htmlhttp://www.blogjava.net/wangxinsh55/comments/259229.htmlhttp://www.blogjava.net/wangxinsh55/archive/2009/03/11/259229.html#feedback1http://www.blogjava.net/wangxinsh55/comments/commentrss/259229.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/259229.html配置了个定时抓取任务,结果总是抓取三次
从tomcat的log上看到该任务所在的context有三次启动的过程,计划任务也被创建了三次

问题原来出在host的appbase设置上,原来的设置是这样的

<hostname="www.xxx.com"appbase="/usr/local/projects/xxx/"
  
unpackwars="false"autodeploy="true"
  
xmlvalidation="false"xmlnamespaceaware="false">
  
<contextdocbase="web"path=""reloadable="true"workdir="work">
  

  
context>
host>

<hostname="admin.xxx.com"appbase="/usr/local/projects/xxx/"
  
unpackwars="false"autodeploy="true"
  
xmlvalidation="false"xmlnamespaceaware="false">
  
<contextdocbase="admin"path=""reloadable="true"workdir="work">
  

  
context>
host>

改成不设置appbase,只对指定的context设置docbase就ok了

<hostname="www.xxx.com"appbase=""
  
unpackwars="false"autodeploy="true"
  
xmlvalidation="false"xmlnamespaceaware="false">
  
<contextdocbase="/usr/local/projects/xxx/web"path=""reloadable="true"workdir="work">
  

  
context>
host>

<hostname="admin.xxx.com"appbase=""
  
unpackwars="false"autodeploy="true"
  
xmlvalidation="false"xmlnamespaceaware="false">
  
<contextdocbase="/usr/local/projects/xxx/admin"path=""reloadable="true"workdir="work">
  

  
context>

为什么不设置appbase就ok来呢?

因为设置了appbase就会自动去加载底下所有的项目


simone 2009-03-11 22:09
]]>
tomcat下 共享session (摘自网上,没有具体验证,如果哪位验证了,请告知一下谢谢)http://www.blogjava.net/wangxinsh55/archive/2009/03/06/258199.htmlsimonesimonefri, 06 mar 2009 06:23:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2009/03/06/258199.htmlhttp://www.blogjava.net/wangxinsh55/comments/258199.htmlhttp://www.blogjava.net/wangxinsh55/archive/2009/03/06/258199.html#feedback3http://www.blogjava.net/wangxinsh55/comments/commentrss/258199.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/258199.html

我们采取的是集中管理的办法。主要技术:

1.设置context 的crosscontext="true",使得各个web应用的servletcontext是可以互访的

               unpackwars="true" autodeploy="true"
        xmlvalidation="false" xmlnamespaceaware="false">


2.主动设置cookies,设置jsessionid为被共享的session的id,统一利用requestsessionid在指定的一个 servletcontext里的一个map查找对于的session,需要存取attribute都对取得的session操作

3.用监听器监听属性的失效



blogjava-凯发k8网页登录

因为最近的项目要用到多web服务器实现访问负载和集群,负载调度使用的是lvs,而非apache的负载调度,因为在高访问量和大并发量的时候lvs的 性能比apache好。然后在web服务器上是使用tomcat5.5.25做应用服务器,对于tomcat的集群有两种方式,这个主要是针对 session而言的。一种就是sticky模式,即黏性会话模式;另外一种就是session复制模式了。所谓sticky模式就是说同一个用户的访问 请求都被派送到同一个tomcat实例上,这样我们就无须在多台服务器之间实现session共享了,这是其好处,不好的地方就是不能实现 failureover了,一但用户访问的机器挂掉,那么其session就会丢失。而session复制模式就可以很好的解决failureover的 问题,即使某一台web服务器挂掉了,用户的请求还会被负载到其他的web服务器上,而且session也被复制了,这样对用户而言就像是在同一台机器上 操作一样,不好的地方就是session复制需要系统资源和网络的开销,尤其是当web服务器多的时候或session里存储的数据量大的时候,这点将会 比较的明显(不过自己还没有做这方面的测试)。

针对这两种方式的弊端和好处,我们可以采用将两种方式结合的方式来达到更好的效果,那 就是sticky session复制模式了。用户的请求按照 sticky方式被分发到同一个web服务器上,同时tomcat在后台做异步复制(非同步)session到其他web服务器,这样我们使用 sticky的简便性,同时又有了一定的容错能力。

下面我就将自己的tomcat集群配置经验跟大家分享一下,呵呵。现在想来,其实tomcat的集群配置真的是非常简单,几乎不需要改什么东西了。我今天就在windows上用一台机器来跑两个tomcat实例,下面是一些基础条件:
1.两个tomcat的目录分别为:d:\apache-tomcat-5.5.25-node1和d:\apache-tomcat-5.5.25-node2
2.在每个tomcat目录下的conf\catalina\localhost目录下建立一个root.xml文件,其内容为:
1
2 3 privileged="true" antiresourcelocking="false" antijarlocking="false" distributable="true">
4


3.修改apache-tomcat-5.5.25-node1的connector端口为8091,修改apache-tomcat-5.5.25-node2的connector的端口为8092,这样是为了避免在同一机器上同时启动时造成访问端口冲突;
4.修改apache-tomcat-5.5.25-node2的server端口为8006,与apache-tomcat-5.5.25-node1的server端口8005不一样,也是避免两个tomcat实例启动时造成程序端口的冲突问题;
5.修改apache-tomcat-5.5.25-node2的ajp/1.3的端口为8019或其他非8009(默认)的端口,也是为了避免与apache-tomcat-5.5.25-node1的ajp/1.3端口冲突;

这 样,我们就可以保证每一个tomcat单独启动时都可以提供d:/mywebapps/test1的web服务,注意是单个启动哦,然后分别启动 apache-tomcat-5.5.25-node1和apache-tomcat-5.5.25-node2后,输入如下地址分别进行访问你的web 应用:
apache-tomcat-5.5.25-node1的访问地址:http://localhost:8091/你的页面地址
apache-tomcat-5.5.25-node2的访问地址:http://localhost:8092/你的页面地址
如果你的tomcat没能成功的提供服务,那么你就需要查看一下是否tomcat部署成功了。注意这里的d:/mywebapps/test1就是你的web应用的物理路径了,可以随意修改。下面就开始对server.xml文件的配置了。

找到apache-tomcat-5.5.25-node1目录下的server.xml文件,打开并找到配置engine的位置,我们在最后加入 jvmroute="node1",表示这个tomcat的实例名称为node1。修改前后的对比如下:

修改前:

修改后:


然 后找到cluster标签,并取消它的注释即可,无须做任何修改。同样,我们修改apache-tomcat-5.5.25-node2下的 server.xml文件,修改jvmroute="node2",然后也是注释掉cluster标签,注意,然后还要修改cluster标签下的 receiver标签的tcplistenport端口号,我们改为4002(默认的是4001),这个是为了避免两个tomcat实例同时启动时造成冲 突。

通过上面的配置后,我们两个tomcat已经配置完毕,并且可以完成集群任务了。注意启动的时候不能直接双击其bing目录下的 startup.bat文件,我们还需要为每一个tomcat设置环境变量,分别在apache-tomcat-5.5.25-node1和 apache-tomcat- 5.5.25-node2的根目录下编写一个bat文件,内容如下:

apache-tomcat-5.5.25-node1目录下的startup_node1.bat内容:
set catalina_home=d:\apache-tomcat-5.5.25-node1
bin/startup.bat

apache-tomcat-5.5.25-node2目录下的startup_node2.bat内容:
set catalina_home=d:\apache-tomcat-5.5.25-node2
bin/startup.bat

然后分别运行这两批处理文件即可正常启动tomcat了。我们先启动node1,双击startup_node1.bat启动node1。我们可以在窗口的最上面看到如下的输出信息:
2008-1-4 19:12:24 org.apache.catalina.cluster.tcp.simpletcpcluster start
信息: cluster is about to start
2008-1-4 19:12:25 org.apache.catalina.cluster.tcp.replicationtransmitter start
信息: start clustersender at cluster catalina:type=cluster,host=localhost with n
ame catalina:type=clustersender,host=localhost
2008-1-4 19:12:25 org.apache.catalina.cluster.mcast.mcastserviceimpl setupsocket

信息: setting cluster mcast sotimeout to 500
2008-1-4 19:12:25 org.apache.catalina.cluster.mcast.mcastservice start
信息: sleeping for 2000 milliseconds to establish cluster membership
2008-1-4 19:12:27 org.apache.catalina.cluster.mcast.mcastservice registermbean
信息: membership mbean registered (catalina:type=clustermembership,host=localhos
t)
2008-1-4 19:12:27 org.apache.catalina.cluster.deploy.farmwardeployer start
信息: cluster farmwardeployer started.
2008-1-4 19:12:29 org.apache.catalina.cluster.session.deltamanager start
信息: starting clustering manager...:
2008-1-4 19:12:29 org.apache.catalina.cluster.session.deltamanager start
信息: register manager to cluster element host with name localhost
2008-1-4 19:12:29 org.apache.catalina.cluster.session.deltamanager start
信息: starting clustering manager at
2008-1-4 19:12:29 org.apache.catalina.cluster.session.deltamanager getallcluster
sessions
信息: manager []: skipping state transfer. no members active in cluster group.

这表明我们的tomcat集群已经正常启动了。然后我们再运行apache-tomcat-5.5.25-node2目录下的startup_node2.bat以启动node2。然后我们可以可以在窗口的最上方看到如下的信息输出:
2008-1-4 19:16:32 org.apache.catalina.cluster.tcp.simpletcpcluster start
信息: cluster is about to start
2008-1-4 19:16:32 org.apache.catalina.cluster.tcp.replicationtransmitter start
信息: start clustersender at cluster catalina:type=cluster,host=localhost with n
ame catalina:type=clustersender,host=localhost
2008-1-4 19:16:32 org.apache.catalina.cluster.mcast.mcastserviceimpl setupsocket

信息: setting cluster mcast sotimeout to 500
2008-1-4 19:16:32 org.apache.catalina.cluster.mcast.mcastservice start
信息: sleeping for 2000 milliseconds to establish cluster membership
2008-1-4 19:16:32 org.apache.catalina.cluster.tcp.simpletcpcluster memberadded
信息: replication member added:org.apache.catalina.cluster.mcast.mcastmember[tcp
://192.168.1.227:4001,catalina,192.168.1.227,4001, alive=245203]
2008-1-4 19:16:34 org.apache.catalina.cluster.mcast.mcastservice registermbean
信息: membership mbean registered (catalina:type=clustermembership,host=localhos
t)
2008-1-4 19:16:34 org.apache.catalina.cluster.deploy.farmwardeployer start
信息: cluster farmwardeployer started.
2008-1-4 19:16:35 org.apache.catalina.cluster.session.deltamanager start
信息: starting clustering manager...:
2008-1-4 19:16:35 org.apache.catalina.cluster.session.deltamanager start
信息: register manager to cluster element host with name localhost
2008-1-4 19:16:35 org.apache.catalina.cluster.session.deltamanager start
信息: starting clustering manager at
2008-1-4 19:16:35 org.apache.catalina.cluster.session.deltamanager getallcluster
sessions
警告: manager [], requesting session state from org.apache.catalina.cluster.mcas
t.mcastmember[tcp://192.168.1.227:4001,catalina,192.168.1.227,4001, alive=248203
]. this operation will timeout if no session state has been received within 60 s
econds.
2008-1-4 19:16:35 org.apache.catalina.cluster.session.deltamanager waitforsendal
lsessions

请注意node2窗口输出的不同颜色部分,这个已经表示node2节点和node2节点联系上了。我们再回过来看node1窗口的输出信息,发现多出了如下的信息:
2008-1-4 19:16:34 org.apache.catalina.cluster.tcp.simpletcpcluster memberadded
信息: replication member added:org.apache.catalina.cluster.mcast.mcastmember[tcp
://192.168.1.227:4002,catalina,192.168.1.227,4002, alive=0]
这 表明node1也已经侦听到了node2,两个tomcat服务器已经建立了联系。然后我们访问node1的一个地址a,假设这个地址a往 session里设置一个属性,然后我们再在同一窗口中访问node2的一个地址b,假设b是从session里读取这个属性,我们会发现b地址确实得到 了这个刚刚我们在node1上设置进去的值。这里要特别注意的是,我们两个地址的分别访问必须是在同一个窗口中,因为我们没有做前端的web负载,所以使 用不同的窗口进行访问会出现不同的session(因为端口号不一样,也就导致访问地址不一样了),这样就导致无法查看的问题。



simone 2009-03-06 14:23
]]>
tomcat 配置集锦http://www.blogjava.net/wangxinsh55/archive/2008/03/12/185627.htmlsimonesimonewed, 12 mar 2008 03:10:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2008/03/12/185627.htmlhttp://www.blogjava.net/wangxinsh55/comments/185627.htmlhttp://www.blogjava.net/wangxinsh55/archive/2008/03/12/185627.html#feedback0http://www.blogjava.net/wangxinsh55/comments/commentrss/185627.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/185627.html阅读全文

simone 2008-03-12 11:10
]]>
tomcat6路径配置心得http://www.blogjava.net/wangxinsh55/archive/2007/08/11/136122.htmlsimonesimonesat, 11 aug 2007 15:22:00 gmthttp://www.blogjava.net/wangxinsh55/archive/2007/08/11/136122.htmlhttp://www.blogjava.net/wangxinsh55/comments/136122.htmlhttp://www.blogjava.net/wangxinsh55/archive/2007/08/11/136122.html#feedback2http://www.blogjava.net/wangxinsh55/comments/commentrss/136122.htmlhttp://www.blogjava.net/wangxinsh55/services/trackbacks/136122.html在tomcat6路径配置中,要通过对tomcat_home\conf\server.xml中的标签中进行设置。具体是这样的:

            unpackwars="true" autodeploy="true"
            xmlvalidation="false" xmlnamespaceaware="false">


这样将站点设置到e:\javaproject\eclipse33project\test目录下边。这时默认的网站根目录是root。如果需要设置其它的虚拟目录,需要在tomcat_home/conf/[enginename]/[hostname]/[网站根目录名].xml设置。
如在tomcat_home/conf/catalina/localhost/webroot.xml下加如下内容:


也可以不需要设置webroot.xml文件,但必须要有tomcat_home/conf/catalina/localhost的文件,这样与最初安装tomcat的webapps文件设置相同(我个人认为)


标签下设置标签如下:

            unpackwars="true" autodeploy="true"
            xmlvalidation="false" xmlnamespaceaware="false">
            
       



这样只可以设定特定的标签中虚拟路径。如果e:\javaproject\eclipse33project\test目录下还有其它的目录如app2,如果没有在标签下设置标签,则无法打开其虚拟路径。


所有context的实现支持如下属性:

属性 描述
backgroundprocessordelay 这个值代表在context及其子容器(包括所有的wrappers)上调用backgroundprocess方法的延时,以秒为单位。如果延时值非负,子容器不会被调用,也就是说子容器使用自己的处理线程。如果该值为正,会创建一个新的线程。在等待指定的时间以后,该线程在主机及其 子容器上调用backgroundprocess方法。context利用后台处理session过期,监测类的变化用于重新载入。如果没有指定,该属性的缺省值是-1,说明context依赖其所属的host的后台处理。
classname 实现的java类名。该类必须实现org.apache.catalina.context接口。如果没有指定,使用标准实现(在下面定义)。
cookies

如果想利用cookies来传递session identifier(需要客户端支持cookies),设为ture。否则为false,这种情况下只能依靠url rewriting传递session identifier。

 

crosscontext

如果想在应用内调用servletcontext.getcontext()来返回在该虚拟主机上运行的其他web application的request dispatcher,设为true。在安全性很重要的环境中,设为false,使得getcontext()总是返回null。缺省值为false。

docbase

该web应用的文档基准目录(document base,也称为context root),或者是war文件的路径。可以使用绝对路径,也可以使用相对于context所属的host的appbase路径。

 

override

如果想利用该context元素中的设置覆盖defaultcontext中相应的设置,设为true。缺省情况下使用defaultcontext中的设置。

privileged

设为true,允许context使用container servlets,比如manager servlet。

 

path

web应用的context路径。catalina将每个url的起始和context path进行比较,选择合适的web应用处理该请求。特定host下的context path必须是惟一的。如果context path为空字符串(""),这个context是所属host的缺省web应用,用来处理不能匹配任何context path的请求。

 

reloadable 如果希望catalina监视/web-inf/classes/和/web-inf/lib下面的类是否发生变化,在发生变化的时候自动重载web application,设为true。这个特征在开发阶段很有用,但也大大增加了服务器的开销。因此,在发布以后,不推荐使用。但是,你可以使用manager应用在必要的时候触发应用的重载。
wrapperclass

org.apache.catalina.wrapper实现类的名称,用于该context管理的servlets。如果没有指定,使用标准的缺省值。

 



simone 2007-08-11 23:22
]]>
网站地图