`
talentkep
  • 浏览: 100468 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

jboss,tomcat,jetty 容器的classloader机制

    博客分类:
阅读更多

背景

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

 

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

问题1: (jar sealed问题)

Java代码 复制代码
  1. Caused by: java.lang.SecurityException: sealing violation:  package  com.sun.media.jai.util is sealed   
  2.         at java.net.URLClassLoader.defineClass(URLClassLoader.java: 234 )   
  3.         at java.net.URLClassLoader.access$ 000 (URLClassLoader.java: 58 )   
  4.         at java.net.URLClassLoader$ 1 .run(URLClassLoader.java: 197 )   
  5.         at java.security.AccessController.doPrivileged(Native Method)   
  6.         at java.net.URLClassLoader.findClass(URLClassLoader.java: 190 )   
  7.         at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java: 419 )   
  8.         at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java: 381 )   
  9.         at java.lang.ClassLoader.defineClass1(Native Method)   
  10.         at java.lang.ClassLoader.defineClassCond(ClassLoader.java: 632 )  
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解析) 

Java代码 复制代码
  1. Caused by: java.lang.NoSuchMethodError: javax.xml.parsers.SAXParserFactory.newInstance(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljavax/xml/parsers/SAXParserFactory;  
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代码 复制代码
  1. java.lang.reflect.InvocationTargetException   
  2.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)   
  3.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 39 )   
  4.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 25 )   
  5.     at java.lang.reflect.Method.invoke(Method.java: 597 )   
  6.     at org.eclipse.jetty.start.Main.invokeMain(Main.java: 490 )   
  7.     at org.eclipse.jetty.start.Main.start(Main.java: 634 )   
  8.     at org.eclipse.jetty.start.Main.parseCommandLine(Main.java: 280 )   
  9.     at org.eclipse.jetty.start.Main.main(Main.java: 82 )   
  10. Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found   
  11.     at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java: 134 )   
  12.     at org.eclipse.jetty.xml.XmlParser.<init>(XmlParser.java: 68 )   
  13.     at org.eclipse.jetty.xml.XmlConfiguration.initParser(XmlConfiguration.java: 79 )   
  14.     at org.eclipse.jetty.xml.XmlConfiguration.<init>(XmlConfiguration.java: 112 )   
  15.     at org.eclipse.jetty.xml.XmlConfiguration$ 1 .run(XmlConfiguration.java: 1028 )   
  16.     at java.security.AccessController.doPrivileged(Native Method)   
  17.     at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java: 983 )   
  18.     ...  8  more  
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问题) 

Java代码 复制代码
  1. Caused by: java.lang.ClassNotFoundException: javax.mail.event.TransportListener   
  2.         at java.net.URLClassLoader$ 1 .run(URLClassLoader.java: 202 )   
  3.         at java.security.AccessController.doPrivileged(Native Method)   
  4.         at java.net.URLClassLoader.findClass(URLClassLoader.java: 190 )   
  5.         at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java: 419 )   
  6.         at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java: 381 )   
  7.         ...  78  more  
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有更明显的对比,这里就主要介绍三个参数代码层面上的实现:

 

 

Xml代码 复制代码
  1. < server >     
  2.       
  3.     <!-- Tomcat 5 Service-->   
  4.     < mbean   code = "org.jboss.web.tomcat.tc5.Tomcat5"   
  5.        name = "jboss.web:service=WebServer"   xmbean-dd = "META-INF/webserver-xmbean.xml" >   
  6. ......   
  7.   
  8. <!-- Get the flag indicating if the normal Java2 parent first class   
  9.            loading model should be used over the servlet 2.3 web container first   
  10.            model.   
  11.       -- >   
  12.        < attribute   name = "Java2ClassLoadingCompliance" > false </ attribute >   
  13.       <!-- A flag indicating if the JBoss Loader should be used. This loader   
  14.            uses a unified class loader as the class loader rather than the tomcat   
  15.            specific class loader.   
  16.            The default is false to ensure that wars have isolated class loading   
  17.            for duplicate jars and jsp files.   
  18.       -- >   
  19.        < attribute   name = "UseJBossWebLoader" > true </ attribute >   
  20.       <!-- The list of package prefixes that should not be loaded without   
  21.          delegating to the parent class loader before trying the web app   
  22.          class loader. The packages listed here are those tha are used by   
  23.          the web container implementation and cannot be overriden. The format   
  24.          is a comma separated list of the package names. There cannot be any   
  25.          whitespace between the package prefixes.   
  26.          This setting only applies when  UseJBossWebLoader = false .   
  27.       -- >   
  28.        < attribute   name = "FilteredPackages" > javax.servlet,org.apache.commons.logging </ attribute >   
  29.   
  30. .....   
  31.   
  32. </ server >   
<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)
    Java代码 复制代码
    1. if  (ctxPath.equals( "/" ) || ctxPath.equals( "/ROOT" ) || ctxPath.equals( "" ))   
    2.       {   
    3.          log.debug( "deploy root context="  + ctxPath);   
    4.          ctxPath =  "/" ;   
    5.          metaData.setContextRoot(ctxPath);   
    6.       }   
    7.   
    8.       URL url =  new  URL(warUrl);   
    9.   
    10.       ClassLoader loader = Thread.currentThread().getContextClassLoader();   
    11.        /* If we are using the jboss class loader we need to augment its path  
    12.       to include the WEB-INF/{lib,classes} dirs or else scoped class loading  
    13.       does not see the war level overrides. The call to setWarURL adds these  
    14.       paths to the deployment UCL.  
    15.       */   
    16.       Loader webLoader =  null ;   
    17.        if  (config.isUseJBossWebLoader())   // 这里对useJbossWebLoader进行判断,进行不同的classloader处理   
    18.       {   
    19.          WebCtxLoader jbossLoader =  new  WebCtxLoader(loader);   
    20.          jbossLoader.setWarURL(url);   
    21.          webLoader = jbossLoader;   
    22.       }   
    23.        else   
    24.       {   
    25.          String[] pkgs = config.getFilteredPackages();   
    26.          WebAppLoader jbossLoader =  new  WebAppLoader(loader, pkgs);   
    27.          jbossLoader.setDelegate(getJava2ClassLoadingCompliance());   
    28.          webLoader = jbossLoader;   
    29.       }  
    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";
    Java代码 复制代码
    1. if  (webLoader !=  null )   
    2.       {   
    3.          server.setAttribute(objectName,  new  Attribute( "loader" , webLoader));   
    4.       }   
    5.        else   
    6.       {   
    7.          server.setAttribute(objectName,  new  Attribute( "parentClassLoader" , loader));   
    8.       }   
    9.   
    10.       server.setAttribute(objectName,  new  Attribute( "delegate" new  Boolean(getJava2ClassLoadingCompliance())));  // 设置deletegate属性   
    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去装载
    Java代码 复制代码
    1. WebCtxLoader(ClassLoader encLoader)   
    2.     {   
    3.            this .encLoader = encLoader;   
    4.            this .ctxLoader =  new  ENCLoader(encLoader);   
    5.           ClassLoader parent = encLoader;   
    6.            while  ((parent  instanceof  RepositoryClassLoader) ==  false  && parent !=  null )   
    7.          parent = parent.getParent();   
    8.            this .delegate = (RepositoryClassLoader) parent;  //delegate对象设置   
    9.     }   
    10.   
    11.   
    12. public   void  setWarURL(URL warURL)  throws  MalformedURLException   
    13.     {   
    14.            this .warURL = warURL;   
    15.           String path = warURL.getFile();   
    16.           File classesDir =  new  File(path,  "WEB-INF/classes" );   
    17.            if  (classesDir.exists())   
    18.           {   
    19.          delegate.addURL(classesDir.toURL());  //无非都是委托给delegate loader   
    20.          ctxLoader.addURLInternal(classesDir.toURL());   
    21.           }   
    22.           File libDir =  new  File(path,  "WEB-INF/lib" );   
    23.            if  (libDir.exists())   
    24.           {   
    25.          File[] jars = libDir.listFiles();   
    26.           int  length = jars !=  null  ? jars.length :  0 ;   
    27.           for  ( int  j =  0 ; j < length; j++)   
    28.          {   
    29.             delegate.addURL(jars[j].toURL());  //无非都是委托给delegate loader   
    30.             ctxLoader.addURLInternal(jars[j].toURL());   
    31.          }   
    32.           }   
    33.        }  
    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控制。
    Java代码 复制代码
    1. public   class  WebAppLoader  extends  org.apache.catalina.loader.WebappLoader   
    2. {   
    3.     private  String[] filteredPackages = {   
    4.        "org.apache.commons.logging"   
    5.    };   
    6.   
    7.     public  WebAppLoader()   
    8.    {   
    9.        super ();   
    10.       setLoaderClass(WebAppClassLoader. class .getName());   
    11.    }   
    12. .....   
    13. }  
    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()
    Java代码 复制代码
    1. public   synchronized   void  start() {   
    2. .....   
    3.   
    4. if  (getLoader() ==  null ) {   
    5.             WebappLoader webappLoader =  new  WebappLoader(getParentClassLoader());   
    6.             webappLoader.setDelegate(getDelegate());   
    7.             setLoader(webappLoader);   
    8.         }   
    9. .....   
    10. }  
    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
    Java代码 复制代码
    1. // Construct a class loader based on our current repositories list   
    2.          try  {   
    3.   
    4.             classLoader = createClassLoader();   
    5.             classLoader.setResources(container.getResources());   
    6.             classLoader.setDelegate( this .delegate);   
    7.             classLoader.setSearchExternalFirst(searchExternalFirst);   
    8.             .....   
    9.              for  ( int  i =  0 ; i < repositories.length; i++) {   
    10.                 classLoader.addRepository(repositories[i]);   
    11.             }   
    12. }<SPAN style= "WHITE-SPACE: normal" > </SPAN>  
    // 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。
相关代码:
Java代码 复制代码
  1. // (0.1) Check our previously loaded class cache   
  2.     clazz = findLoadedClass(name);   
  3.   
  4. // (0.2) Try loading the class with the system class loader, to prevent the webapp from overriding J2SE classes   
  5.     clazz = system.loadClass(name);   
  6.   
  7.   boolean  delegateLoad = delegate || filter(name);   
  8. // (1) Delegate to our parent if requested   
  9. if  (delegateLoad) {   
  10.     ClassLoader loader = parent;   
  11.              if  (loader ==  null )   
  12.                 loader = system;   
  13.              try  {   
  14.                 clazz = loader.loadClass(name);   
  15.         ....   
  16.         }   
  17.      .....   
  18. }   
  19.   
  20. // (2) Search local repositories   
  21. clazz = findClass(name);   
  22.   
  23. // (3) Delegate to parent unconditionally   
  24. if  (!delegateLoad) {   
  25.     ClassLoader loader = parent;   
  26.              if  (loader ==  null )   
  27.                 loader = system;   
  28.              try  {   
  29.                 clazz = loader.loadClass(name);   
  30.         ....   
  31.         }   
  32.      .....   
  33. }  
// (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
    Java代码 复制代码
    1. public   void  preConfigure()  throws  Exception   
    2.     {   
    3.          // Setup configurations   
    4.         loadConfigurations();   
    5.   
    6.          // Setup system classes   
    7.         loadSystemClasses();   
    8.            
    9.          // Setup server classes   
    10.         loadServerClasses();   
    11.   
    12.          // Configure classloader   
    13.         _ownClassLoader= false ;   
    14.          if  (getClassLoader()== null )   
    15.         {   
    16.             WebAppClassLoader classLoader =  new  WebAppClassLoader( this );   
    17.             setClassLoader(classLoader);   
    18.             _ownClassLoader= true ;   
    19.         }   
    20. .....   
    21. }  
    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进行装载
    Java代码 复制代码
    1. (_context.isParentLoaderPriority() || system_class) && !server_class)  
    (_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优先加载。
    默认值代码 复制代码
    1. public final static String[] __dftServerClasses =    
    2.     {   
    3.          "-org.eclipse.jetty.continuation." , // don't hide continuation classes   
    4.          "-org.eclipse.jetty.jndi." ,         // don't hide naming classes   
    5.          "-org.eclipse.jetty.plus.jaas." ,    // don't hide jaas classes   
    6.          "-org.eclipse.jetty.websocket." ,    // don't hide websocket extension   
    7.          "-org.eclipse.jetty.servlet.DefaultServlet" , // don't hide default servlet   
    8.          "org.eclipse.jetty."                 // hide other jetty classes   
    9.     } ; <SPAN style= "WHITE-SPACE: normal" > </SPAN>  
    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进行装载。
    默认值代码 复制代码
    1. public final static String[] __dftSystemClasses =    
    2.     {   
    3.          "java." ,                            // Java SE classes (per servlet spec v2. 5  / SRV. 9.7 . 2 )    
    4.          "javax." ,                           // Java SE classes (per servlet spec v2. 5  / SRV. 9.7 . 2 )   
    5.          "org.xml." ,                         // needed by javax.xml   
    6.          "org.w3c." ,                         // needed by javax.xml   
    7.          "org.apache.commons.logging." ,      // TODO: review if special case still needed    
    8.          "org.eclipse.jetty.continuation." ,  // webapp cannot change continuation classes   
    9.          "org.eclipse.jetty.jndi." ,          // webapp cannot change naming classes   
    10.          "org.eclipse.jetty.plus.jaas." ,     // webapp cannot change jaas classes   
    11.          "org.eclipse.jetty.websocket." ,     // WebSocket is a jetty extension   
    12.          "org.eclipse.jetty.servlet.DefaultServlet"   // webapp cannot change default servlets   
    13.     } ;  
    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
    Xml代码 复制代码
    1. < Call   name = "setAttribute" >   
    2.        < Arg > org.eclipse.jetty.webapp.systemClasses </ Arg >   
    3.        < Arg >   
    4.            < Array   type = "java.lang.String" >   
    5.                < Item > java. </ Item >   
    6.           ......   
    7.        </ Array   
    8.        </ Arg >   
    9. </ Call >   
    <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

 

Html代码 复制代码
  1. 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.    
  2. A package might be sealed to ensure version consistency among the classes in your software or as a security measure.   
  3. To seal a package, a Name header needs to be added for the package, followed by a Sealed header, similar to this:   
  4. Name: myCompany/myPackage/   
  5. Sealed: true   
  6.   
  7. The Name header's value is the package's relative pathname. Note that it ends with a '/' to distinguish it from a filename.   
    分享到:
    评论

相关推荐

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

    #### 深入理解Servlet引擎:JBoss与Tomcat、Jetty的协同机制 在JavaWeb技术领域,Servlet引擎扮演着至关重要的角色,它们负责执行Servlet,处理HTTP请求并生成响应。其中,JBoss、Tomcat和Jetty是最为广泛使用的...

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

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

    jboss 5 原理 2 classloader

    随着OSGi(Open Services Gateway Initiative)风格的类加载机制逐渐流行,以及新的Java模块和类加载规范的出现,JBoss对自身的类加载层进行了重构,以适应这些新的需求。在JBoss Microcontainer中,类加载层扮演着...

    apache 集成 jboss、tomcat

    Apache作为前端服务器处理静态内容,而动态内容由JBoss或Tomcat处理。这种架构提供了更高的性能和可扩展性。在这个场景中,我们重点关注Windows环境下的集成,主要涉及Apache的mod_jk模块。 1. **Apache mod_jk模块...

    JBOSS+TOMCAT集成开发环境。完整版

    【JBOSS+TOMCAT集成开发环境】是一种常见的企业级应用服务器组合,它结合了JBOSS的全面中间件服务和TOMCAT的轻量级Servlet容器特性,为开发者提供了一个高效且灵活的开发与部署平台。在这个“完整版”中,用户可以...

    Apache+Jboss(Tomcat)集群配置

    - **Jboss/Tomcat**:Jboss是Java EE应用服务器,Tomcat是轻量级的Servlet容器,两者都可以运行Java Web应用程序。这里可以使用Jboss-4.0.4.GA版本,或者与Apache配合的Tomcat版本。 - **Apache Tomcat Connector ...

    tomcate和jetty虚拟目录配置方法

    在Java Web开发中,Tomcat和Jetty是两种常见的应用服务器。它们都支持虚拟目录配置,使得我们可以将多个Web应用程序部署在同一服务器上,而无需更改全局服务器配置。虚拟目录允许我们为每个应用设置一个独立的URL...

    Apache Tomcat JBOSS Nginx区别

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

    J2EE应用服务器Jboss+Tomcat安装攻略

    J2EE应用服务器是企业级Java应用程序开发和部署的核心平台,而Jboss和Tomcat的组合提供了一种开源且稳定的选择。Jboss是一款强大的J2EE应用服务器,它支持多种J2EE规范,如EJB(Enterprise JavaBeans)、JMS(Java ...

    TOMCAT移植到JBOSS

    ### 知识点详解:“TOMCAT移植到JBOSS” #### 1. **Web应用服务器的概念** 在探讨从TOMCAT移植到JBOSS的过程中,我们首先需要理解Web应用服务器的基本概念。Web应用服务器是运行Java Web应用程序的平台,如...

    Jetty和tomcat比较.docx

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

    JBOSS\Tomcat最大连接数配置和jvm内存配置.docx

    【JBOSSTomcat最大连接数配置和JVM内存配置】 在JBOSSTomcat服务器的性能优化中,最大连接数配置和JVM内存配置是两个至关重要的环节,它们直接影响到服务器的响应速度和稳定性,尤其对于处理大量并发请求的场景。 ...

    WebLogic、WebSphere、JBOSS、Tomcat之间的区别

    Tomcat 不支持 EJB,JBoss 是实现了 EJB 容器,再集成了 Tomcat。WebLogic 与 WebSphere 都是对业内多种标准的全面支持,包括 EJB、JSB、JMS、JDBC、XML 和 WML,使 Web 应用系统的实施更为简单,并且保护了投资,...

    tomcat_Jboss_weblogic区别、容器的作用

    "Tomcat、Jboss、Weblogic区别、容器的作用" Tomcat是一种免费的开放源代码的Web应用服务器,它是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及...

    tomcat-and-jboss.rar_jboss_tomcat

    【标题】:“Tomcat与JBoss的对比分析” 【描述】:在IT行业中,Tomcat和JBoss都是广泛使用的应用程序服务器,它们各自有着独特的特性和优势。Tomcat以其轻量级、高效能和对Servlet及JavaServer Pages(JSP)的良好...

    CXF发布WebService,jboss和tomcat都能发布

    - **tomcat**:Tomcat是Apache软件基金会的项目,是一款轻量级的Servlet容器,支持Servlet和JSP标准。 - **cxf**:Apache CXF是一个用于构建和部署Web服务的开源框架,支持多种协议,包括SOAP和REST。 - **...

    jBoss+tomcat学习笔记大全,jBoss+tomcat的帮助文档

    ### jBoss + Tomcat 学习笔记大全及帮助文档概览 #### 一、环境搭建与配置 在开始深入探讨jBoss与Tomcat的集成之前,我们先来了解如何搭建基本的开发环境。 ##### 1. Java 环境配置 - **安装 J2SDK1.4+ 和 J2...

    java项目tomcat迁移到jboss

    Java 项目从 Tomcat 迁移到 JBoss 的解决方案 在 Java 项目中,迁移到 JBoss 可能会出现各种问题,例如版本兼容问题、设置问题等。本文将介绍如何解决这些问题,包括如何配置 JBoss,使得 Spring 项目能够正常运行...

    Tomcat容器

    Tomcat容器,全称为Apache Tomcat,是一款开源且免费的Java Web应用服务器,由Apache软件基金会的Jakarta项目开发和维护。它是实现Java Servlet和JavaServer Pages(JSP)规范的主要容器之一,是Java EE(现更名为...

    jboss4版本修复Apache Tomcat DIGEST身份验证多个安全漏洞(CVE-2012-3439)升级包

    jboss4版本下,jbossweb-tomcat55.sar升级包,修复Apache Tomcat DIGEST身份验证多个安全漏洞(CVE-2012-3439) 升级包中的jar来源于tomcat5.5.36 使用方法:直接替换jboss中旧的jbossweb-tomcat55.sar

Global site tag (gtag.js) - Google Analytics