`
yjhexy
  • 浏览: 331070 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

tomcat 类加载机制 —— ClassLoader

阅读更多

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


 

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

 

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

 

 public synchronized Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException {

        if (log.isDebugEnabled())
            log.debug("loadClass(" + name + ", " + resolve + ")");
        Class clazz = null;

        // Log access to stopped classloader
        if (!started) {
            try {
                throw new IllegalStateException();
            } catch (IllegalStateException e) {
                log.info(sm.getString("webappClassLoader.stopped", name), e);
            }
        }

        // (0) Check our previously loaded local class cache.从先前已经加载的本地 cache中查找该类
        clazz = findLoadedClass0(name);
        if (clazz != null) {
            if (log.isDebugEnabled())
                log.debug("  Returning class from cache");
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.1) Check our previously loaded class cache .从先前已经加载cache中查找该类
        clazz = findLoadedClass(name);
        if (clazz != null) {
            if (log.isDebugEnabled())
                log.debug("  Returning class from cache");
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.2) Try loading the class with the system class loader, to prevent
        //       the webapp from overriding J2SE classes
        // 尝试从system class loader中加载,保护j2se 的核心类。
        try {
            clazz = system.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

        // (0.5) Permission to access this class when using a SecurityManager
        if (securityManager != null) {
            int i = name.lastIndexOf('.');
            if (i >= 0) {
                try {
                    securityManager.checkPackageAccess(name.substring(0,i));
                } catch (SecurityException se) {
                    String error = "Security Violation, attempt to use " +
                        "Restricted Class: " + name;
                    log.info(error, se);
                    throw new ClassNotFoundException(error, se);
                }
            }
        }

        boolean delegateLoad = delegate || filter(name);

        // (1) Delegate to our parent if requested
        // 如果delegate被设置为true的话委托给双亲加载
        if (delegateLoad) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader1 " + parent);
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        // (2)从WEB-INF/lib  ,WEB-INF/classes加载类
        if (log.isDebugEnabled())
            log.debug("  Searching local repositories");
        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (log.isDebugEnabled())
                    log.debug("  Loading class from local repository");
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            ;
        }

        // (3) Delegate to parent unconditionally
        // 如果本地找不到需要加载的类,则还是委托双亲去加载该类
        if (!delegateLoad) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader at end: " + parent);
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        throw new ClassNotFoundException(name);

    }

 那么在哪里用到了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;

    }

 

  • 大小: 36.7 KB
分享到:
评论
1 楼 playinlife 2010-07-27  
StandardWrapper.java又是什么呢?

相关推荐

    2021Java大厂面试题——大厂真题之携程-Java高级.pdf

    在Tomcat服务器中,类的加载方式与JVM的标准类加载机制有所不同。Tomcat采用了更加细粒度的类加载策略,以支持更复杂的Web应用程序部署。 **1. Tomcat中的类加载器** 当Tomcat启动时,会创建几种类加载器: - **...

    面试必问之jvm与性能优化.pdf

    在Tomcat服务器中,类的加载机制有所不同,主要包括以下几种类型的类加载器: - **Bootstrap ClassLoader**:加载JVM启动所需的核心类和标准扩展类。 - **System ClassLoader**:加载Tomcat启动所需的类文件,如`...

    Tomcat中JNDI原理

    Tomcat通过`org.apache.naming.ContextBindings`类实现了JNDI中的`ContextBinding`机制。`ContextBindings`类负责维护一个`java.util.Hashtable`,用于存储和管理ClassLoader级别的上下文绑定信息。这允许每个应用或...

    tomcat工作原理-组件

    Tomcat使用自定义的ClassLoader来加载Web应用的类。每个Web应用都有自己的ClassLoader,这样可以避免不同应用之间的类冲突。ClassLoader还会处理应用的依赖管理,加载JAR文件中的类。 5. **StandardServer和...

    java超有用的面试题目

    - **Classloader**:包括启动类加载器、扩展类加载器、应用类加载器等,采用双亲委派机制。 #### Java内存模型与并发应用 - **指令重排序**:为了优化性能,编译器和处理器可能会重新排列指令执行顺序。 - **内存...

    帆软V9getshell1

    - 动态加载并执行解密后的类文件,实现远程代码执行。 3. **HTTP请求示例**:攻击者通过发送如下POST请求将恶意代码写入指定位置: ``` POST /WebReport/ReportServer? op=svginit&cmd=design_save_svg&...

    Spring.3.x企业应用开发实战(完整版).part2

    3.2.2 类装载器ClassLoader 3.2.3 Java反射机制 3.3 资源访问利器 3.3.1 资源抽象接口 3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 ...

    Spring3.x企业应用开发实战(完整版) part1

    3.2.2 类装载器ClassLoader 3.2.3 Java反射机制 3.3 资源访问利器 3.3.1 资源抽象接口 3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 ...

Global site tag (gtag.js) - Google Analytics