我在从 Tomcat 6 迁移到 Tomcat 7 时遇到了这个问题。Ricky over-here改进了一个几乎对我有用的解决方案。我必须改进它才能为我工作。我改变了他的听众小赌注,它就像一个魅力。我希望它可以帮助其他人:
导入java.io.File;
导入 java.io.IOException;
导入 java.net.JarURLConnection;
导入 java.net.URL;
导入 java.util.Enumeration;
导入 java.util.HashSet;
导入 java.util.Set;
导入 java.util.jar.JarEntry;
导入 java.util.jar.JarFile;
导入 javax.servlet.ServletContext;
导入 javax.servlet.ServletContextEvent;
导入 javax.servlet.ServletContextListener;
导入 javax.servlet.ServletRegistration;
导入 javax.servlet.http.HttpServlet;
导入 org.apache.catalina.ContainerServlet;
/**
*
* http://snippets.dzone.com/posts/show/4831
*
* @作者瑞奇
*/
公共类 InvokerLoadListener 实现 ServletContextListener {
/**
* 定义包以搜索 servlet 的调用程序参数。
* 逗号分隔的软件包列表
*/
公共静态最终字符串 PACKAGES_PARAMETER = "invoker.packages";
/**
* 调用者参数设置映射名称。默认情况下是“/servlet/”
*/
公共静态最终字符串 INVOKER_PREFIX_PARAMETER = "invoker.prefix";
/**
* 扫描可从上下文类加载器访问的所有类
* 属于给定的包和子包。
*
* @param 包名
* @return 找到的类列表
*/
私人设置getClasses(字符串包名){
设置类 = new HashSet();
尝试 {
类加载器 classLoader = Thread.currentThread().getContextClassLoader();
字符串路径 = packageName.replace('.', '/');
枚举资源 = classLoader.getResources(path);
而(资源.hasMoreElements()){
URL 资源 = resources.nextElement();
if (resource.getProtocol().equals("jar")) {
// 在 jar 中 => 读取 jar 文件并检查
findClassesJar(资源、路径、类);
} else if (resource.getProtocol().equals("file")) {
// 读取子目录并找到
findClassesFile(new File(resource.getFile()), packageName, classes);
} 别的 {
System.err.println("未知协议连接:" + 资源);
}
}
} 捕捉(IOException e){
e.printStackTrace();
}
返回课程;
}
/**
* 读取一个jar文件并检查其中的所有类与包
* 指定名称。
*
* @param resource 资源地址
* @param 路径
* @param 类
* @返回
*/
private Set findClassesJar(URL resource, String path, Set classes) {
JarURLConnection jarConn = null;
JarFile jar = null;
尝试 {
jarConn = (JarURLConnection) 资源.openConnection();
jar = jarConn.getJarFile();
枚举 e = jar.entries();
而(e.hasMoreElements()){
JarEntry entry = e.nextElement();
if ((entry.getName().startsWith(path + "/")
|| entry.getName().startsWith(path + "."))
&& entry.getName().endsWith(".class")) {
字符串名称 = entry.getName().replace('/', '.');
name = name.substring(0, name.length() - 6);
checkClass(名称,类);
}
}
} 捕捉(IOException e){
e.printStackTrace();
} 最后 {
尝试 {
jar.close();
} 捕捉(IOException e){
}
}
返回课程;
}
/**
* 用于查找给定文件中所有类的递归方法(文件
* 或目录)。
*
* @param file 基本目录
* @param packageName 在基目录中找到的类的包名
* @classes 类列表
* @return 相同的类
* @throws ClassNotFoundException
*/
private Set findClassesFile(File file, String packageName, Set classes) {
if (file.isFile() && file.getName().endsWith(".class")) {
//classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
checkClass(packageName.substring(0, packageName.length() - 6), 类);
} 别的 {
文件[] 文件 = file.listFiles();
如果(文件!= null){
对于(文件 f:文件){
findClassesFile(f, packageName + "." + f.getName(), classes);
}
}
}
返回课程;
}
私人设置检查类(字符串名称,设置类){
尝试 {
类 clazz = Class.forName(name);
//将AND更改为OR
if (HttpServlet.class.isAssignableFrom(clazz)
|| ContainerServlet.class.isAssignableFrom(clazz)) {
类.add(clazz);
}
} 捕捉(ClassNotFoundException e){
e.printStackTrace();
}
返回课程;
}
@Override
公共无效上下文初始化(ServletContextEvent sce){
System.out.println("contextInitialized(ServletContextEvent e)");
ServletContext sc = sce.getServletContext();
字符串列表 = sc.getInitParameter(PACKAGES_PARAMETER);
字符串前缀 = sc.getInitParameter(INVOKER_PREFIX_PARAMETER);
如果(前缀 == null){
前缀 = "/servlet/";
}
如果(列表!= null){
String[] packages = list.split(",");
对于 (int i = 0; i 0) {
System.out.println("检查包:" + packageName);
// 加载 servlet.invoker 下的类
设置类 = getClasses(packageName);
System.out.println("尺寸:" + classes.size());
对于(类 clazz:类){
字符串映射 = 前缀 + clazz.getName();
System.out.println("添加 '" + clazz.getName() + "' 在映射中'" + 映射 + "'");
ServletRegistration sr = sc.getServletRegistration(clazz.getName());
//改变了这个;似乎有时 servlet 已经注册,需要重新映射
如果(sr == null)
sr = sc.addServlet(clazz.getName(), clazz.getName());
如果 ( sr != null )
sr.addMapping(映射);
}
}
}
}
}
@Override
公共无效上下文销毁(ServletContextEvent sce){
System.out.println("contextDestroyed(ServletContextEvent e)");
}
}
干杯