我需要从jar文件加载一些servlet并将其映射到Tomcat中的URL。
Servlet代码是
package net.arturik.mymodulepackage;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "QWERTY", urlPatterns = {"/qqq"})
public class QWERTY extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
/* TODO output your page here. You may use following sample code. */
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet QWERTY</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet QWERTY at " + request.getContextPath() + "</h1>");
out.println("</body>");
out.println("</html>");
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
Servlet编译并存储在MyModulePackage-1.0-SNAPSHOT.jar文件中。
在Java Web App中,我有ServletContextListenerImpl类:
package net.arturik.testosgispring;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;
@WebListener
public class ServletContextListenerImpl implements ServletContextListener {
@Override
public void contextInitialized(final ServletContextEvent sce) {
try {
System.out.println("++++++++++++++");
final ServletContext servletContext = sce.getServletContext();
//////////////////////////////////////////////
String pathToJar = "m:\\myhostingpanel\\myhostingpanel\\Tests\\MyModulePackage\\target\\MyModulePackage-1.0-SNAPSHOT.jar";
JarFile jarFile = new JarFile(pathToJar);
Enumeration e = jarFile.entries();
URL[] urls = {new URL("jar:file:" + pathToJar + "!/")};
URLClassLoader cl = URLClassLoader.newInstance(urls, this.getClass().getClassLoader());
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if (je.isDirectory() || !je.getName().endsWith(".class")) {
continue;
}
// -6 because of .class
String className = je.getName().substring(0, je.getName().length() - 6);
className = className.replace('/', '.');
Class c;
Object obj;
try {
System.out.println("className !!! " + className);
c = cl.loadClass(className);
obj = c.newInstance();
System.out.println(c.getPackage() + " " + c.getName());
Class noparams[] = {};
// Method method = c.getDeclaredMethod("qqq", noparams);
// method.invoke(obj, null);
// MyInter obj1 = (MyInter) c.newInstance();
// obj1.qqq();
System.out.println("registering");
final ServletRegistration.Dynamic dynamic = servletContext.addServlet("QWERTY", c);
dynamic.addMapping("/qqq");
final Map<String, ? extends ServletRegistration> map = servletContext.getServletRegistrations();
for (String key : map.keySet()) {
System.out.println("Registered Servlet: " + map.get(key).getName());
}
System.out.println("end of registering ");
} catch (Exception ex) {
ex.printStackTrace();
}
}
//////////////////////////////////////////////
} catch (IOException ex) {
Logger.getLogger(ServletContextListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void contextDestroyed(final ServletContextEvent sce) {
//NO-OP
}
}
此代码获得输出
++++++++++++++
className !!! net.arturik.mymodulepackage.QWERTY
package net.arturik.mymodulepackage net.arturik.mymodulepackage.QWERTY
registering
Registered Servlet: default
Registered Servlet: jsp
Registered Servlet: QWERTY
Registered Servlet: T1
Registered Servlet: mvc-dispatcher
Registered Servlet: T2
Registered Servlet: T3
end of registering
我们可以看到 - servlet已成功注册。
但是如果我尝试打开page / qqq,Tomcat就会出现异常
22-Nov-2014 02:07:56.846 SEVERE [http-nio-8082-exec-5] org.apache.catalina.core.StandardWrapperValve.invoke Allocate exception for servlet QWERTY
java.lang.ClassNotFoundException: net.arturik.mymodulepackage.QWERTY
据我所知 - 这是一个类可见性问题 - 我的类由URLClassLoader初始化,我的类没有传递给主(系统)类加载器。
如何将由URLClassLoader加载的类传递给系统类加载器以实现全局可见性?