tomcat 类加载机制 —— ClassLoader

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


 

加载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 <jsp-file> element content in
            // order to be completely effective
            /**
             * <pre>
             * 以下代码为了使类似这样的配置
             * <servlet> 
             *     <servlet-name>Test</servlet-name> 
             *     <jsp-file>/TestPage.jsp</jsp-file>
             * </servlet> 
             * 其中<jsp-file>是用来代替<servlet-class>的
             * </pre>
             */
            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
            // 如果配置文件中<servlet-class>没有指定的话,抛出抱怨
            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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值