tomcat 类加载机制 —— ClassLoader

tomcat 为了做到每个host中都能加载各种不同的WEB应用而不相互影响,采用的类加载机制有所特别:


tomcat 类加载机制 —— ClassLoader_第1张图片

 

加载WEB应用中我们自己写的类的顺序也是按照图中 标示的1243顺序所示。 

 

把WebAppClassLoader.java的loadClass方法贴出来瞧瞧:

 

Java代码   收藏代码
  1. public synchronized Class loadClass(String name, boolean resolve)  
  2.        throws ClassNotFoundException {  
  3.   
  4.        if (log.isDebugEnabled())  
  5.            log.debug("loadClass(" + name + ", " + resolve + ")");  
  6.        Class clazz = null;  
  7.   
  8.        // Log access to stopped classloader  
  9.        if (!started) {  
  10.            try {  
  11.                throw new IllegalStateException();  
  12.            } catch (IllegalStateException e) {  
  13.                log.info(sm.getString("webappClassLoader.stopped", name), e);  
  14.            }  
  15.        }  
  16.   
  17.        // (0) Check our previously loaded local class cache.从先前已经加载的本地 cache中查找该类  
  18.        clazz = findLoadedClass0(name);  
  19.        if (clazz != null) {  
  20.            if (log.isDebugEnabled())  
  21.                log.debug("  Returning class from cache");  
  22.            if (resolve)  
  23.                resolveClass(clazz);  
  24.            return (clazz);  
  25.        }  
  26.   
  27.        // (0.1) Check our previously loaded class cache .从先前已经加载cache中查找该类  
  28.        clazz = findLoadedClass(name);  
  29.        if (clazz != null) {  
  30.            if (log.isDebugEnabled())  
  31.                log.debug("  Returning class from cache");  
  32.            if (resolve)  
  33.                resolveClass(clazz);  
  34.            return (clazz);  
  35.        }  
  36.   
  37.        // (0.2) Try loading the class with the system class loader, to prevent  
  38.        //       the webapp from overriding J2SE classes  
  39.        // 尝试从system class loader中加载,保护j2se 的核心类。  
  40.        try {  
  41.            clazz = system.loadClass(name);  
  42.            if (clazz != null) {  
  43.                if (resolve)  
  44.                    resolveClass(clazz);  
  45.                return (clazz);  
  46.            }  
  47.        } catch (ClassNotFoundException e) {  
  48.            // Ignore  
  49.        }  
  50.   
  51.        // (0.5) Permission to access this class when using a SecurityManager  
  52.        if (securityManager != null) {  
  53.            int i = name.lastIndexOf('.');  
  54.            if (i >= 0) {  
  55.                try {  
  56.                    securityManager.checkPackageAccess(name.substring(0,i));  
  57.                } catch (SecurityException se) {  
  58.                    String error = "Security Violation, attempt to use " +  
  59.                        "Restricted Class: " + name;  
  60.                    log.info(error, se);  
  61.                    throw new ClassNotFoundException(error, se);  
  62.                }  
  63.            }  
  64.        }  
  65.   
  66.        boolean delegateLoad = delegate || filter(name);  
  67.   
  68.        // (1) Delegate to our parent if requested  
  69.        // 如果delegate被设置为true的话委托给双亲加载  
  70.        if (delegateLoad) {  
  71.            if (log.isDebugEnabled())  
  72.                log.debug("  Delegating to parent classloader1 " + parent);  
  73.            ClassLoader loader = parent;  
  74.            if (loader == null)  
  75.                loader = system;  
  76.            try {  
  77.                clazz = loader.loadClass(name);  
  78.                if (clazz != null) {  
  79.                    if (log.isDebugEnabled())  
  80.                        log.debug("  Loading class from parent");  
  81.                    if (resolve)  
  82.                        resolveClass(clazz);  
  83.                    return (clazz);  
  84.                }  
  85.            } catch (ClassNotFoundException e) {  
  86.                ;  
  87.            }  
  88.        }  
  89.   
  90.        // (2)从WEB-INF/lib  ,WEB-INF/classes加载类  
  91.        if (log.isDebugEnabled())  
  92.            log.debug("  Searching local repositories");  
  93.        try {  
  94.            clazz = findClass(name);  
  95.            if (clazz != null) {  
  96.                if (log.isDebugEnabled())  
  97.                    log.debug("  Loading class from local repository");  
  98.                if (resolve)  
  99.                    resolveClass(clazz);  
  100.                return (clazz);  
  101.            }  
  102.        } catch (ClassNotFoundException e) {  
  103.            ;  
  104.        }  
  105.   
  106.        // (3) Delegate to parent unconditionally  
  107.        // 如果本地找不到需要加载的类,则还是委托双亲去加载该类  
  108.        if (!delegateLoad) {  
  109.            if (log.isDebugEnabled())  
  110.                log.debug("  Delegating to parent classloader at end: " + parent);  
  111.            ClassLoader loader = parent;  
  112.            if (loader == null)  
  113.                loader = system;  
  114.            try {  
  115.                clazz = loader.loadClass(name);  
  116.                if (clazz != null) {  
  117.                    if (log.isDebugEnabled())  
  118.                        log.debug("  Loading class from parent");  
  119.                    if (resolve)  
  120.                        resolveClass(clazz);  
  121.                    return (clazz);  
  122.                }  
  123.            } catch (ClassNotFoundException e) {  
  124.                ;  
  125.            }  
  126.        }  
  127.   
  128.        throw new ClassNotFoundException(name);  
  129.   
  130.    }  

 那么在哪里用到了WebAppClassLoader呢,见下面的代码,代码贴的比较长。但是比较重点的:

 StandardWrapper.java

    /**
     * Load and initialize an instance of this servlet, if there is not already at least one initialized instance. This
     * can be used, for example, to load servlets that are marked in the deployment descriptor to be loaded at server
     * startup time.
     */
    public synchronized Servlet loadServlet() throws ServletException {

        // Nothing to do if we already have an instance or an instance pool
        // 初始化servlet的时候,如果发现已经初始化完毕,则不再初始化
        if (!singleThreadModel && (instance != null)) return instance;

        // 把标准输出重定向
        PrintStream out = System.out;
        if (swallowOutput) {
            SystemLogHandler.startCapture();
        }

        Servlet servlet;
        try {
            long t1 = System.currentTimeMillis();
            // If this "servlet" is really a JSP file, get the right class.
            // HOLD YOUR NOSE - this is a kludge that avoids having to do special
            // case Catalina-specific code in Jasper - it also requires that the
            // servlet path be replaced by the  element content in
            // order to be completely effective
            /**
             * 
             * 以下代码为了使类似这样的配置
             *  
             *     Test 
             *     /TestPage.jsp
             *  
             * 其中是用来代替的
             * 
*/ String actualClass = servletClass; if ((actualClass == null) && (jspFile != null)) { Wrapper jspWrapper = (Wrapper) ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME); if (jspWrapper != null) { actualClass = jspWrapper.getServletClass(); // Merge init parameters String paramNames[] = jspWrapper.findInitParameters(); for (int i = 0; i < paramNames.length; i++) { if (parameters.get(paramNames[i]) == null) { parameters.put(paramNames[i], jspWrapper.findInitParameter(paramNames[i])); } } } } // Complain if no servlet class has been specified // 如果配置文件中没有指定的话,抛出抱怨 if (actualClass == null) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.notClass", getName())); } // Acquire an instance of the class loader to be used // 获取一个CLASS LOADER来搞,一般获得的是WebAppClassLoader Loader loader = getLoader(); if (loader == null) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.missingLoader", getName())); } ClassLoader classLoader = loader.getClassLoader(); // Special case class loader for a container provided servlet if (isContainerProvidedServlet(actualClass) && !((Context) getParent()).getPrivileged()) { // If it is a priviledged context - using its own // class loader will work, since it's a child of the container // loader classLoader = this.getClass().getClassLoader(); } // Load the specified servlet class from the appropriate class loader Class classClass = null; try { if (SecurityUtil.isPackageProtectionEnabled()) { final ClassLoader fclassLoader = classLoader; final String factualClass = actualClass; try { classClass = (Class) AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws Exception { if (fclassLoader != null) { return fclassLoader.loadClass(factualClass); } else { return Class.forName(factualClass); } } }); } catch (PrivilegedActionException pax) { Exception ex = pax.getException(); if (ex instanceof ClassNotFoundException) { throw (ClassNotFoundException) ex; } else { getServletContext().log("Error loading " + fclassLoader + " " + factualClass, ex); } } } else { if (classLoader != null) { // 使用WebAppClassLoader加载实际的类 classClass = classLoader.loadClass(actualClass); } else { classClass = Class.forName(actualClass); } } } catch (ClassNotFoundException e) { unavailable(null); getServletContext().log("Error loading " + classLoader + " " + actualClass, e); throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass), e); } if (classClass == null) { unavailable(null); throw new ServletException(sm.getString("standardWrapper.missingClass", actualClass)); } // Instantiate and initialize an instance of the servlet class itself try { // 创建一个Servlet实例 servlet = (Servlet) classClass.newInstance(); // Annotation processing if (!((Context) getParent()).getIgnoreAnnotations()) { if (getParent() instanceof StandardContext) { ((StandardContext) getParent()).getAnnotationProcessor().processAnnotations(servlet); ((StandardContext) getParent()).getAnnotationProcessor().postConstruct(servlet); } } } catch (ClassCastException e) { unavailable(null); // Restore the context ClassLoader throw new ServletException(sm.getString("standardWrapper.notServlet", actualClass), e); } catch (Throwable e) { unavailable(null); // Added extra log statement for Bugzilla 36630: // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 if (log.isDebugEnabled()) { log.debug(sm.getString("standardWrapper.instantiate", actualClass), e); } // Restore the context ClassLoader throw new ServletException(sm.getString("standardWrapper.instantiate", actualClass), e); } // Check if loading the servlet in this web application should be // allowed if (!isServletAllowed(servlet)) { throw new SecurityException(sm.getString("standardWrapper.privilegedServlet", actualClass)); } // Special handling for ContainerServlet instances if ((servlet instanceof ContainerServlet) && (isContainerProvidedServlet(actualClass) || ((Context) getParent()).getPrivileged())) { ((ContainerServlet) servlet).setWrapper(this); } classLoadTime = (int) (System.currentTimeMillis() - t1); // Call the initialization method of this servlet try { // 触发servlet的beforeInit事件 instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet); if (Globals.IS_SECURITY_ENABLED) { Object[] args = new Object[] { ((ServletConfig) facade) }; SecurityUtil.doAsPrivilege("init", servlet, classType, args); args = null; } else { // 触发servlet初始化操作 servlet.init(facade); } // Invoke jspInit on JSP pages if ((loadOnStartup >= 0) && (jspFile != null)) { // Invoking jspInit DummyRequest req = new DummyRequest(); req.setServletPath(jspFile); req.setQueryString(Constants.PRECOMPILE + "=true"); DummyResponse res = new DummyResponse(); if (Globals.IS_SECURITY_ENABLED) { Object[] args = new Object[] { req, res }; SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args); args = null; } else { servlet.service(req, res); } } // 触发afterInit初始化操作 instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet); } catch (UnavailableException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); unavailable(f); throw f; } catch (ServletException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw f; } catch (Throwable f) { getServletContext().log("StandardWrapper.Throwable", f); instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw new ServletException(sm.getString("standardWrapper.initException", getName()), f); } // Register our newly initialized instance // singleTheadModel纯粹没用的东西,不用考虑了 singleThreadModel = servlet instanceof SingleThreadModel; if (singleThreadModel) { if (instancePool == null) instancePool = new Stack(); } fireContainerEvent("load", this); loadTime = System.currentTimeMillis() - t1; } finally { if (swallowOutput) { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { if (getServletContext() != null) { getServletContext().log(log); } else { out.println(log); } } } } return servlet; }


转载:http://yjhexy.iteye.com/blog/668334

http://blog.csdn.net/joeyon1985/article/details/38978251

你可能感兴趣的:(jvm)