Java Se之类加载问题思考

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LookAtClassLoaderServlet
 */
public class LookAtClassLoaderServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LookAtClassLoaderServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		PrintWriter out = response.getWriter();
		ClassLoader classLoader = this.getClass().getClassLoader();
		while(classLoader != null){
			out.write(classLoader.getClass().getName() + "<br>");
			classLoader = classLoader.getParent();
		}
		out.append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

这是tomcat启动之后访问此servlet打印出来的结果:

org.apache.catalina.loader.WebappClassLoader
java.net.URLClassLoader
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader

将LookAtClassLoaderServlet打成jar放到jvm ext文件下,然后再重新启动tomcat,访问此servlet就会报错500。如下:

java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet
.......
.......
root cause java.lang.ClassNotFoundException:javax.servlet.http.HttpServlet
......
.......

是因为这个servlet的父类HttpServlet也需要加载,但是这里要注意谁去加载它?回到刚开始成功的地方看一下,org.apache.catalina.loader.WebappClassLoader这是tomcat的类加载器,根据双亲委派机制,先是需要委托给父加载器让父辈们对类进行加载找不到才会往下也就是子类加载器去加载。那么上面的,LookAtClassLoaderServlet以及他的父类HttpServlet都是有org.apache.catalina.loader.WebappClassLoader进行加载的。

当把servlet打成jar放到虚拟机的扩展目录下,那么此时sun.misc.Launcher$ExtClassLoader会进行加载,当加载到LookAtClassLoaderServlet父类HttpServlet,它并找不到。这个时候它是不会让子类去加载的所以此时只能抛出错误。(类走到哪一级类加载器加载,那么它所继承的父类同时也需要这个类加载器去加载。)

我们知道,当HttpServlet是在…Tomcat 8.0libservlet-api.jar里面,所以此时我们将它拷贝到jdk jre的 lib 目录下ext目录下 ;重新启动 tomcat容器,进行访问,结果就成了:sun.misc.Launcher$ExtClassLoader

原文地址:https://www.cnblogs.com/Kevin-1992/p/12608448.html