`
agapple
  • 浏览: 1595514 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

主流web容器(jetty,tomcat,jboss)的classloader机制对比和相关问题分析

    博客分类:
  • java
阅读更多

背景

     前段时间一直在做应用容器的迁移,将公司的应用容器从jboss,tomcat统一迁移到jetty。在整个迁移过程中遇到最多的潜在问题还是在classloader机制上,这里记录一下希望能对大家有所帮助,避免重复走弯路。

 

啥都不说,先来看下遇到的几个问题,比较纠结的问题。

问题1: (jar sealed问题)

Caused by: java.lang.SecurityException: sealing violation: package com.sun.media.jai.util is sealed
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:234)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:419)
        at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:381)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)

说明: jboss容器运行正常 , jetty容器运行出错

 

问题2:  (xml解析) 

Caused by: java.lang.NoSuchMethodError: javax.xml.parsers.SAXParserFactory.newInstance(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljavax/xml/parsers/SAXParserFactory;

说明: jetty容器运行正常 , tomcat容器运行正常,jboss容器运行异常

 

问题3:  (xml解析) 

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.jetty.start.Main.invokeMain(Main.java:490)
	at org.eclipse.jetty.start.Main.start(Main.java:634)
	at org.eclipse.jetty.start.Main.parseCommandLine(Main.java:280)
	at org.eclipse.jetty.start.Main.main(Main.java:82)
Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found
	at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:134)
	at org.eclipse.jetty.xml.XmlParser.<init>(XmlParser.java:68)
	at org.eclipse.jetty.xml.XmlConfiguration.initParser(XmlConfiguration.java:79)
	at org.eclipse.jetty.xml.XmlConfiguration.<init>(XmlConfiguration.java:112)
	at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1028)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:983)
	... 8 more

说明: jboss容器运行正常 , jetty容器运行异常

 

问题4:(mail问题) 

Caused by: java.lang.ClassNotFoundException: javax.mail.event.TransportListener
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:419)
        at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:381)
        ... 78 more

说明: jboss容器运行正常 , jetty容器运行异常 

 

可以说基本都是对应的class , method等找不到,或者类冲突等问题,一看就是比较典型的classloader引发的问题。


下面就来看看对容器classloader机制的分析和对比,相信大家了解了相关classloader机制微妙的区别后,基本也能解析这一类问题了

jboss4.05 classloader机制

这里早期对jboss classloader几点配置做了下说明,可以参见: http://agapple.iteye.com/blog/791940

 

为了和tomcat,jetty有更明显的对比,这里就主要介绍三个参数代码层面上的实现:

 

 

<server> 
   
   <!-- Tomcat 5 Service-->
   <mbean code="org.jboss.web.tomcat.tc5.Tomcat5"
      name="jboss.web:service=WebServer" xmbean-dd="META-INF/webserver-xmbean.xml">
......

<!-- Get the flag indicating if the normal Java2 parent first class
           loading model should be used over the servlet 2.3 web container first
           model.
      -->
      <attribute name="Java2ClassLoadingCompliance">false</attribute>
      <!-- A flag indicating if the JBoss Loader should be used. This loader
           uses a unified class loader as the class loader rather than the tomcat
           specific class loader.
           The default is false to ensure that wars have isolated class loading
           for duplicate jars and jsp files.
      -->
      <attribute name="UseJBossWebLoader">true</attribute>
      <!-- The list of package prefixes that should not be loaded without
         delegating to the parent class loader before trying the web app
         class loader. The packages listed here are those tha are used by
         the web container implementation and cannot be overriden. The format
         is a comma separated list of the package names. There cannot be any
         whitespace between the package prefixes.
         This setting only applies when UseJBossWebLoader=false.
      -->
      <attribute name="FilteredPackages">javax.servlet,org.apache.commons.logging</attribute>

.....

</server>

 

 

相信这几个参数大家都应该比较熟知,配置项在 deploy/jbossweb-tomcat55.sar/META-INF/jboss-service.xml中

 

下面循着代码来看一下jboss的相关实现:

  1. 代码入口: org.jboss.web.tomcat.tc5.Tomcat5, 这里的三个配置都对应于Tomcat5类的属性,默认值就是当前配置的值。
  2. Tomcat5会创建一个Deploy进行war包的装载,TomcatDeployer(继承于AbstractWebDeployer)
    if (ctxPath.equals("/") || ctxPath.equals("/ROOT") || ctxPath.equals(""))
          {
             log.debug("deploy root context=" + ctxPath);
             ctxPath = "/";
             metaData.setContextRoot(ctxPath);
          }
    
          URL url = new URL(warUrl);
    
          ClassLoader loader = Thread.currentThread().getContextClassLoader();
          /* If we are using the jboss class loader we need to augment its path
          to include the WEB-INF/{lib,classes} dirs or else scoped class loading
          does not see the war level overrides. The call to setWarURL adds these
          paths to the deployment UCL.
          */
          Loader webLoader = null;
          if (config.isUseJBossWebLoader())  // 这里对useJbossWebLoader进行判断,进行不同的classloader处理
          {
             WebCtxLoader jbossLoader = new WebCtxLoader(loader);
             jbossLoader.setWarURL(url);
             webLoader = jbossLoader;
          }
          else
          {
             String[] pkgs = config.getFilteredPackages();
             WebAppLoader jbossLoader = new WebAppLoader(loader, pkgs);
             jbossLoader.setDelegate(getJava2ClassLoadingCompliance());
             webLoader = jbossLoader;
          }
     
  3. 最后通过MBean调用,将classloader设置给对应的tomcat上下文对象: "org.apache.catalina.core.StandardContext";
    if (webLoader != null)
          {
             server.setAttribute(objectName, new Attribute("loader", webLoader));
          }
          else
          {
             server.setAttribute(objectName, new Attribute("parentClassLoader", loader));
          }
    
          server.setAttribute(objectName, new Attribute("delegate", new Boolean(getJava2ClassLoadingCompliance()))); // 设置deletegate属性

说明:

  • WebCtxLoader: 一个对jboss UCL classloader的一个代理而已,setWarUrl也只是将war资源加入到当前jboss的UCL classloader去装载
    WebCtxLoader(ClassLoader encLoader)
       	{
    	      this.encLoader = encLoader;
    	      this.ctxLoader = new ENCLoader(encLoader);
    	      ClassLoader parent = encLoader;
    	      while ((parent instanceof RepositoryClassLoader) == false && parent != null)
    		 parent = parent.getParent();
    	      this.delegate = (RepositoryClassLoader) parent; //delegate对象设置
    	}
    
    
    public void setWarURL(URL warURL) throws MalformedURLException
       	{
    	      this.warURL = warURL;
    	      String path = warURL.getFile();
    	      File classesDir = new File(path, "WEB-INF/classes");
    	      if (classesDir.exists())
    	      {
    		 delegate.addURL(classesDir.toURL()); //无非都是委托给delegate loader
    		 ctxLoader.addURLInternal(classesDir.toURL());
    	      }
    	      File libDir = new File(path, "WEB-INF/lib");
    	      if (libDir.exists())
    	      {
    		 File[] jars = libDir.listFiles();
    		 int length = jars != null ? jars.length : 0;
    		 for (int j = 0; j < length; j++)
    		 {
    		    delegate.addURL(jars[j].toURL()); //无非都是委托给delegate loader
    		    ctxLoader.addURLInternal(jars[j].toURL());
    		 }
    	      }
    	   }
  • WebAppLoader: 对tomcat WebappLoader的一个封装, 同时设置filteredPackages给tomcat WebappLoader进行class控制。
    public class WebAppLoader extends org.apache.catalina.loader.WebappLoader
    {
       private String[] filteredPackages = {
          "org.apache.commons.logging"
       };
    
       public WebAppLoader()
       {
          super();
          setLoaderClass(WebAppClassLoader.class.getName());
       }
    .....
    }
     

看到这里大家相信应该差不多了解了,总结一下: 

  1. java2ClassLoadingCompliance是针对useJbossWebLoader=false时而言,是通过设置tomcat WebappClassloader的是否delegate进行控制classloader,实现child first/parent first。
  2. java2ClassLoadingCompliance在useJBossWebLoader=true时,不会生效,会被强制设置为false,具体可看WebCtxLoaders,实现了Loader接口,getClassLoader()返回的是一个ctxLoader对jboss WebLoader的一个包装。
  3. filteredPackages目前是通过tomcat的classloader机制上进行控制,所以只能是在useJbossWebLoader=false时有效,因为依赖了tomcat的实现。

不过需要注意两点:

  1. 目前在jboss4.05上不支持在在war包下WEB-INF/jboss-web.xml的配置,在jboss4.20以后才支持,可见https://jira.jboss.org/browse/JBAS-3047?subTaskView=all
  2. jboss 5.0以后,就没有UseJbossWebLoader这一配置项了,实现方式也不是delegate到tomcat,而是独立的一个classloader,统一处理。
jboss classloader机制大家也不必太刻意的去学习,只要适当的了解基本使用。只能说一切都是浮云浮云,随时都可能被改变。

 

tomcat6.0.30 classloader机制 

tomcat相比于jboss4.05概念上简介了很多,不过tomcat 6版本相比于tomcat 5有一些变化,少了一些shared lib库的概念。

 

      Bootstrap
          |
       System
          |
       Common
       /     \
  Webapp1   Webapp2 ... 

 一个树状结构,相信大家差不多都知道tomcat默认是以child first装载class,优先载入web中的class类,找不到才会去装载公用类。

 

下面就来看一下代码的一些实现: 

 

  1. tomcat启动入口,通过分析StandardContext.start()
    public synchronized void start() {
    .....
    
    if (getLoader() == null) {
                WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
                webappLoader.setDelegate(getDelegate());
                setLoader(webappLoader);
            }
    .....
    }
  2. 如果getLoader为空,则创建一个新的WebappLoader,注意这也是jboss设置tomcat loader的入口,从而替换默认的tomcat classloader。
  3. WebappLoader通过在startInternal启动了一个新的WebappClassLoader
    // Construct a class loader based on our current repositories list
            try {
    
                classLoader = createClassLoader();
                classLoader.setResources(container.getResources());
                classLoader.setDelegate(this.delegate);
                classLoader.setSearchExternalFirst(searchExternalFirst);
                .....
                for (int i = 0; i < repositories.length; i++) {
                    classLoader.addRepository(repositories[i]);
                }
    } 
  4. 最后就是WebappClassLoader的loadClass方法了,具体的类装载策略。
下面来看一下,loadClass的相关逻辑: 
  1. (0.1)先检查class是否已经被装载过,findLoadedClass
  2. (0.2)通过system classloader装载系统class,所以这里会优先装载jdk的相关代码,这个很重要,也很特别
  3. 如果是delegate=true并且不是filterPackage列表,则采用parent first,否则采用child first。
相关代码:
// (0.1) Check our previously loaded class cache
	clazz = findLoadedClass(name);

// (0.2) Try loading the class with the system class loader, to prevent the webapp from overriding J2SE classes
	clazz = system.loadClass(name);

 boolean delegateLoad = delegate || filter(name);
// (1) Delegate to our parent if requested
if (delegateLoad) {
	ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
	    ....
 	    }
     .....
}

// (2) Search local repositories
clazz = findClass(name);

// (3) Delegate to parent unconditionally
if (!delegateLoad) {
	ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
	    ....
 	    }
     .....
}
 

最后总结一下, 两个参数配置:

  1. delegate(child first/parent first),默认值为false,即为child first
  2. packageTriggers,执行child first时,排除的package列表,如果匹配了package,即时为delegate=false,也会优先执行parent first策略。
  3. tomcat的classloader机制在处理class装载时,会优先尝试使用system进行装载,这样可以优先使用jdk的相关类,这也是问题2的原因。

 

jetty7.1.20 classloader机制

jetty与tomcat相比,没有太大上的区别,也是有parent first/child first的概念,filter package等。但还是有些小区别,那先看一下代码:

  1. jetty启动入口org.eclipse.jetty.server.Server,通过DeploymentManager进行webapps目录的加载
  2. 具体war包加载是通过WebAppProvider,通过createContextHandler创建应用上下文WebAppContext。
  3. WebAppContext在初始化时,创建WebAppClassLoader
    public void preConfigure() throws Exception
        {
            // Setup configurations
            loadConfigurations();
    
            // Setup system classes
            loadSystemClasses();
            
            // Setup server classes
            loadServerClasses();
    
            // Configure classloader
            _ownClassLoader=false;
            if (getClassLoader()==null)
            {
                WebAppClassLoader classLoader = new WebAppClassLoader(this);
                setClassLoader(classLoader);
                _ownClassLoader=true;
            }
    .....
    }
  4. 最后就是WebAppClassLoader的loadclass方法了。
理解了这些基本概念后,jetty的loadclass方法,逻辑比较好理解:
  1. 如果属于system_class或者_parentLoaderPriority=true,并且不是server_class,优先采用parent first进行装载
    (_context.isParentLoaderPriority() || system_class) && !server_class)
  2. 否则采用child first,先由WebAppClassLoader进行装载,没找到class再交由父CL装载

里面的有几个概念:

  •  _parentLoaderPriority: 对应child first/parent first。
  • _serverClasses : jetty系统实现类,jetty认为服务实现类,必须在WEB-INF/lib , WEB-INF/classes优先加载。
    public final static String[] __dftServerClasses = 
        {
            "-org.eclipse.jetty.continuation.", // don't hide continuation classes
            "-org.eclipse.jetty.jndi.",         // don't hide naming classes
            "-org.eclipse.jetty.plus.jaas.",    // don't hide jaas classes
            "-org.eclipse.jetty.websocket.",    // don't hide websocket extension
            "-org.eclipse.jetty.servlet.DefaultServlet", // don't hide default servlet
            "org.eclipse.jetty."                // hide other jetty classes
        } ;  
  • __dftSystemClasses :  系统类,类似于tomcat的filterPackage,优先采取parent first进行装载。
    public final static String[] __dftSystemClasses = 
        {
            "java.",                            // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) 
            "javax.",                           // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
            "org.xml.",                         // needed by javax.xml
            "org.w3c.",                         // needed by javax.xml
            "org.apache.commons.logging.",      // TODO: review if special case still needed 
            "org.eclipse.jetty.continuation.",  // webapp cannot change continuation classes
            "org.eclipse.jetty.jndi.",          // webapp cannot change naming classes
            "org.eclipse.jetty.plus.jaas.",     // webapp cannot change jaas classes
            "org.eclipse.jetty.websocket.",     // WebSocket is a jetty extension
            "org.eclipse.jetty.servlet.DefaultServlet"  // webapp cannot change default servlets
        } ;

相关配置: 

  • _parentLoaderPriority的变量,可以通过环境变量org.eclipse.jetty.server.webapp.parentLoaderPriority=false/true
  • server_class和system_class,可以通过设置Server attributes
    <Call name="setAttribute">
          <Arg>org.eclipse.jetty.webapp.systemClasses</Arg>
          <Arg>
              <Array type="java.lang.String">
                  <Item>java.</Item>
    	      ......
    	  </Array
          </Arg>
    </Call>

 

总结和对比一下(jboss,tomcat,jetty)容器的classloader机制

容器 jboss(4.05) tomcat(6.0.30) jetty(7.1.20)
支持child/parent first设置(默认值) Java2ClassLoadingCompliance=false delegate=false _parentLoaderPriority=false
过滤package配置 FilteredPackages
默认值: javax.servlet,org.apache.commons.logging
packageTriggers
默认配置:org.apache.commons.logging
systemClasses
默认配置:java. 
javax.
org.xml.
org.w3c.
org.apache.commons.logging.
org.eclipse.jetty.continuation.
org.eclipse.jetty.jndi.
org.eclipse.jetty.plus.jaas.
org.eclipse.jetty.websocket.
org.eclipse.jetty.servlet.DefaultServlet.
特殊性

1. UseJBossWebLoader=false时,过滤packages才能生效

2. UseJBossWebLoader=true时,不支持过滤packages

3. jboss 5.0以后UseJBossWebLoader参数将不支持

1. 在执行child/parent判断之前,会委托system classloader装载系统class,比如jdk的lib库

1. 多了一个serverclass配置,如果是serverclass优先采用child first

2. systemclass默认的配置,多了javax,org.xml,org.w3c配置。

相关文档 svn url : http://anonsvn.jboss.org/repos/jbossas/tags/JBoss_4_0_5_GA_CP18
jboss社区classloader文档: http://community.jboss.org/wiki/ClassLoadingConfiguration

svn url : http://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk

官方classloader机制: http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html

svn url : http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/tags/jetty-7.2.0.v20101020/

classloader 官方文档: http://docs.codehaus.org/display/JETTY/Classloading

 
 

 

最后(相关问题分析)

 

问题1:

  是一个jar sealed问题, 官方说明: http://download.oracle.com/javase/tutorial/deployment/jar/sealman.html

 

Package Sealing: A package within a JAR file can be optionally sealed, which means that all classes defined in that package must be archived in the same JAR file. 
A package might be sealed to ensure version consistency among the classes in your software or as a security measure.
To seal a package, a Name header needs to be added for the package, followed by a Sealed header, similar to this:
Name: myCompany/myPackage/
Sealed: true

The Name header's value is the package's relative pathname. Note that it ends with a '/' to distinguish it from a filename. 
Any headers following a Name header, without any intervening blank lines, apply to the file or package specified in the Name header. 
In the above example, because the Sealed header occurs after the Name: myCompany/myPackage header, 
with no blank lines between, the Sealed header will be interpreted as applying (only) to the package myCompany/myPackage. 

This code doesn't work.

 

说白了就是jdk在jar层面上做的一层控制,避免出现两个不同版本的实现类同时在应用中被装载。

理清了sealed的含义,再看一下出错的堆栈:com.sun.media.jai.util,这个类是jai相关处理

  • jai_core.jar
  • jai_codec.jar
  • jai_imageio.jar

几个jar包的META-INF/MANIFEST.MF中都定义了sealed :true。而我们的应用中刚好有两个jar包,那为什么在jboss运行中没问题,jetty运行却出了问题。

 

最后的原因:

1. 我们使用的是javax.media.jai.JAI.create(String opName,ParameterBlock args),该类刚好依赖了com.sun.media.jai.util.ImagingListenerImpl等相关类。

2. 意看jetty的特殊性,针对javax.media.jai.JAI是属于systemclass,所以会优先使用jdk去装载,而com.sun则通过应用容器装载,很巧的是公司的jdk下的jre/lib/ext下刚好增加了jai的相关jar,最终导致了sealed冲突。

 

解决方案:

   处理起来相对暴力,增加配置systemclass配置,添加jai的相关package,所有的jai都采取parent first加载。

<!--for jai_code.jar , jai_codec.jar -->
<Item>com.sun.media.jai.</Item>
<!--for jai_imageio.jar -->
<Item>com.sun.media.imageio.</Item>
<Item>com.sun.media.imageioimpl.</Item>
<Item>jj2000.j2k.</Item>


问题2

xml加载的问题,原因也跟jetty的特殊性相关。大家都知道xml解析类有很多种

  • xerces
  • crimson
  • jdk rt.jar
  • j2ee.jar

真TMD令人纠结啊,应用容器中一旦同时依赖了这几个xml类库,那麻烦问题就来了。这个SAXParserFactory.newInstance(String factoryClassName, ClassLoader classLoader)在jdk1.6.18版本中有,而在其他的几个包中却没有该接口方法。

 

该问题的原因:

  1. 原先应用运行的是tomca,也因为tomcat容器的特殊性,会优先通过system classloader优先装载,正好SAXParserFactory类属于jdk的库,所以也正好装载了jdk的类
  2. jetty容器因为特殊systemclass配置,针对javax.打头的package采用parent first,所以这时装载了jdk SAXParserFactory
  3. 最后jboss运行时,因为我们使用的是UseJbossWebLoader=true,所以会优先装载应用中的lib,至于用哪个那就看概率了,一般按classpath装载lib的顺序。所以这时没有该方法,就抛出了对应的错误

解决方案:

处理方式也比较粗暴,如果该方法存在歧义,那干脆不用这方法不就得了,最后换用了无参的newInstance()方法。但这时得注意了,不同xml类库,对应的xml impl默认配置不一样。比如jdk的配置:就会以他自己的为默认值

 

return (SAXParserFactory) FactoryFinder.find(
                /* The default property name according to the JAXP spec */
                "javax.xml.parsers.SAXParserFactory",
                /* The fallback implementation class name */
                "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");

 

所以最后为了统一使用,通过设置环境变量:

-Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl

 

问题3:

 该问题是由问题2引出的,正因为设置了xml解析器为xerces,导致在jetty启动的时候出现了一些问题。这次主要的原因就跟共享lib库有关了。

 

最终原因分析:

  1. 因为通过环境变量设置了xml解析器的实现类,所以不同的xml类库在创建xml parse时,都会尝试去载入对应的lib库。
  2. jetty启动时,其自身需要解析xml文件,这时候就出现问题了,jetty默认是没有xerces xml的解析类的,所以启动就出错了。

 

解决方案:

  1. 参照jboss的共享lib的配置,在jetty的ext库里添加了xercesImpl-2.9.1.jar,xml-apis-1.3.04.jar,xml-resolver-1.2.jar
  2. 因为我使用的是外部ext库,不想放到jetty软件的lib库下,所以需要通过手工指定,在start.ini中添加:
    lib=${jettyserverhome}/ext


问题4:

是一个mail邮件发送时发现的问题,从堆栈信息描述看也很见到,对应的javax.mail.event.TransportListener没找到

mail的lib库也是挺让人纠结的

1. xml一样有多个lib库:j2ee.jar,javamail。

2. 但有一点又不同的是j2ee.jar中只有接口申明没有对应的实现类

3. 更纠结的是j2ee-1.4新版本和老的javamail版本接口上还存在差异性(这个是别人告诉我的,个人没仔细验证)

 

看到这,各位看官需要多淡定一下,真是很让人纠结啊

 

最终原先分析:

  1. 原先jboss容器运行没问题,主要是和其默认的lib库有关,jboss 4.05在默认的server/default/lib下有个jboss-j2ee.jar,所以即使容器中没有javamail的包也能正常运行。
  2. 换成jetty以后,因默认在jetty下没有j2ee这个lib库,所以很悲惨,抛异常了。

 

解决方案:

1. 没必要参合j2ee.jar,直接在原先的工程里添加javamail的依赖,最后在应用中引入javamail的包。

 

 

 

 

 结尾

在这次的jetty使用过程,还是遇到了比较多的问题,大部分还是在classloader机制上,希望通过这篇文章能对大家有所帮助,少走弯路。

写的有点小乱,大家将就看一下,如有问题,欢迎拍砖。

ps : 不知不觉已经到1点多了
分享到:
评论
19 楼 sqtds 2014-07-03  
楼主,我看了你的dbcp连接池那块感觉不错,刚刚关了网页,突然想了下,其他文章也应该不错,于是重新打开找到了楼主,果然挺好的,感谢。
18 楼 agapple 2011-07-18  
aids198311 写道
NND,看了遍jetty源码才看懂ljh的文章。V5


其实jetty源码的代码还算比较少的,相比于jboss,看起来也很快。
17 楼 aids198311 2011-07-17  
NND,看了遍jetty源码才看懂ljh的文章。V5
16 楼 csd_ali 2010-12-17  
讲的很透彻。
15 楼 keepgo 2010-12-12  
收藏慢慢看,暂时看不懂
14 楼 hngmduyi 2010-11-30  
收藏一下。慢慢研究。
13 楼 yan3999 2010-11-30  
膜拜下,太高深了
12 楼 kingkan 2010-11-30  
学习了,感谢楼主分享!
11 楼 坏孩子 2010-11-29  
websphere做的比较好,可以选择加载顺序,直接在界面上配置就可以了

不知道jee规范有没有定义类装载顺序,发现jee的规范很多地方都没有定义到,导致迁移的时候经常出现不兼容的问题
10 楼 agapple 2010-11-29  
haitaohehe 写道
楼主把应用从Jboss、tomcat迁移到了jetty ? 这是出于什么考虑呢?


多方面的原因
1. 嵌入式 (目前未上嵌入式,以后是一种趋势,以后应用真的是可以无状态化,随便一个包扔服务器上就能跑)
2. 轻便 (支持options参数,加载最少的模块)
3. 性能 (相比于jboss4.05有一定的提升,30%左右,使用的是jetty NIO connector,不过目前测试在线上测试性比tomcat略差一点)

也说说它的缺点:
1. 代码。 你会看到它的release版本会非常频繁,也说明它的小问题bug比较多。有时你会在代码里看到system.err(message)的代码。
2. 使用nio,系统负载比正常的阻塞io的jboss,tomcat略高一些,比如load,cpu利用率等。
9 楼 haitaohehe 2010-11-29  
honda418 写道
haitaohehe 写道
楼主把应用从Jboss、tomcat迁移到了jetty ? 这是出于什么考虑呢?


启动速度。。。。


不是单纯为了启动速度吧,难道这不是用在生产环境。。。
8 楼 haytalent 2010-11-29  
膜拜楼猪,3Q,十分感谢分享。。
7 楼 ccilt 2010-11-29  
mark...收藏
6 楼 obullxl 2010-11-29  
很受用,楼主V5。
5 楼 honda418 2010-11-29  
haitaohehe 写道
楼主把应用从Jboss、tomcat迁移到了jetty ? 这是出于什么考虑呢?


启动速度。。。。
4 楼 dengzhangtao 2010-11-29  
现在这个对我来说过于高升了。。 汗
3 楼 calvinlyc 2010-11-29  
学习了,谢谢LZ分享,很有用的知识
2 楼 haitaohehe 2010-11-29  
楼主把应用从Jboss、tomcat迁移到了jetty ? 这是出于什么考虑呢?
1 楼 ylsun1113 2010-11-29  
太牛b了!

相关推荐

    Tomcat-JBoss-Weblogic-Jetty的区别和介绍

    Tomcat应用也算非常广泛的web 服务器,支持部分j2ee,免费...JBoss和WebLogic都含有Jsp和Servlet容器,也就可以做web容器, JBoss和WebLogic也包含EJB容器,是完整的J2EE应用服务器 tomcat 只能做jsp和servlet的container

    Apache Tomcat JBOSS Nginx区别

    JBoss 是一个管理 EJB 的容器和服务器,但 JBoss 核心服务不包括支持 servlet/JSP 的 WEB 容器,一般与 Tomcat 或 Jetty 绑定使用。JBoss 与 Web 服务器在同一个 Java 虚拟机中运行,Servlet 调用 EJB 不经过网络,...

    Jetty和tomcat比较.docx

    - **Servlet引擎**: Tomcat和Jetty都是基于Java的Servlet容器,支持标准的servlet规范和JavaEE的规范。这意味着开发者可以在这些容器中部署和运行Java Web应用。 #### 不同点 1. **架构比较** - **Jetty**: ...

    Servlet引擎:JBoss与Tomcat、Jetty协同工作

    其中,JBoss、Tomcat和Jetty是最为广泛使用的Servlet容器,它们各自拥有独特的架构和工作原理,但同时也具备协同工作的能力。 **一、JBoss的基本架构与工作原理** JBoss是一个功能强大的企业级Java应用服务器,其...

    JAVA里使用Jetty作为轻量级嵌入式的Web容器

    Java中的Jetty是一个轻量级、高性能且可嵌入式的Web服务器和Servlet容器,它以其简单易用和高效性在开发社区中广受欢迎。本文将深入探讨Jetty的基本概念、特性以及如何在Java项目中使用它。 1. **Jetty简介** - ...

    how tomcat works和jetty-src和tomcat7-src

    【标题】"how tomcat works和jetty-src和tomcat7-src" 提及了三个关键概念:Tomcat的工作原理、Jetty源代码以及Tomcat 7的源代码。这些是Java Web服务器领域的核心元素,主要涉及到如何处理HTTP请求、部署Web应用...

    websocket+tomcat+jetty+netty

    Tomcat、Jetty和Netty都是支持WebSocket的Java服务器平台,各有其优势和适用场景。理解这些技术可以帮助开发者选择最适合他们项目的解决方案,并且能够有效地利用WebSocket实现高效的实时通信功能。

    SpringBoot切换Tomcat容器,SpringBoot使用Jetty容器

    在Spring Boot框架中,开发者可以选择不同的嵌入式Web服务器作为应用程序的容器,其中最常见的是Tomcat和Jetty。本文将深入探讨如何在Spring Boot项目中从Tomcat切换到Jetty容器,以及这两个容器的特点和使用场景。 ...

    eclipse开发环境(支持tomcat、maven、jetty、JBoss) - - ITeye技术网站

    eclipse开发环境(支持tomcat、maven、jetty、JBoss) - - ITeye技术网站

    jetty,tomcat原理

    Jetty和Tomcat是两个广泛应用的Java Web服务器和Servlet容器,它们在处理HTTP请求、执行Java Servlets以及管理Web应用程序方面起着关键作用。了解这两个容器的工作原理对于开发者来说至关重要,特别是对于面试和职业...

    Jetty web 容器

    **Jetty Web 容器详解** Jetty 是一个开源的、轻量级的 Java Web 应用服务器,它被广泛用于开发、测试和部署Web应用程序。Jetty 的设计目标是小巧、快速、易于集成,使其成为开发人员和小型团队的理想选择。在本文...

    轻量级的 Java Web 容器 Jetty.zip

    Jetty 是一个开源的servlet容器,它为基于Java的web内容,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立...

    容器jetty

    Jetty是一款轻量级、高性能的Java Web服务器和Servlet容器,它在开源社区中广受欢迎,尤其适用于嵌入式系统和分布式应用程序。标题中的"jetty-distribution-9.3.5.v20151012"指的是Jetty的一个发行版本,具体为9.3.5...

    简单迅速的web容器 简单迅速的web容器 简单迅速的web容器

    例如,Tomcat就是一个著名的开源Web容器,它轻便且支持Java Servlet和JavaServer Pages(JSP)。另一个例子是Jetty,也是一个快速、小巧且高效的Web服务器,常用于嵌入式系统。 总结来说,"简单迅速的web容器"是一...

    web容器---servlet

    常见的Web容器有Tomcat、Jetty、JBoss、WebLogic等。Web容器提供了执行Servlet所需的环境,包括处理HTTP请求、管理Servlet生命周期、线程安全等。 2. **Servlet生命周期**:Servlet有三个主要的生命周期方法:`init...

    Eclipse SVN Jetty Tomcat jad 等常用插件

    "Eclipse SVN Jetty Tomcat jad 等常用插件"这个标题提到了几个在Java开发中非常关键的工具和组件,让我们一一解析它们: 1. **SVN(Subversion)**: - SVN是版本控制系统,用于跟踪和管理项目源代码的变更。在...

    如何将xacs从jetty平台移植到tomcat平台

    这里我们选择使用 MySQL 作为数据库,使用 Java 1.7 作为开发语言,并使用 Tomcat 8.0.37 作为 Web 容器。 二、安装数据库 由于 XACS 默认使用 MySQL 数据库,所以我们需要安装 MySQL。在安装完成后,我们使用 ...

    远程上传代码容器jetty

    Jetty是一款轻量级、高性能的Java Web服务器和Servlet容器,它允许开发者快速地部署和管理Web应用程序。在这个场景下,远程上传代码意味着开发人员或自动化工具可以通过HTTP请求将代码文件传输到运行Jetty服务的...

Global site tag (gtag.js) - Google Analytics