您需要实现自己的WebappClassLoaderBase,以便在context.xml 的loader 的配置中定义。
实现你的WebappClassLoaderBase
最简单的方法是将WebappClassLoader扩展为next
package my.package;
public class MyWebappClassLoader extends WebappClassLoader {
public MyWebappClassLoader() {
}
public MyWebappClassLoader(final ClassLoader parent) {
super(parent);
}
@Override
public void start() throws LifecycleException {
String[] paths = {"/WEB-INF/ChildApp1/lib", "/WEB-INF/ChildApp2/lib"};
// Iterate over all the non standard locations
for (String path : paths) {
// Get all the resources in the current location
WebResource[] jars = resources.listResources(path);
for (WebResource jar : jars) {
// Check if the resource is a jar file
if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) {
// Add the jar file to the list of URL defined in the parent class
addURL(jar.getURL());
}
}
}
// Call start on the parent class
super.start();
}
}
部署你的WebappClassLoaderBase
- 使用与您的 tomcat 版本相对应的 tomcat jar 构建您自己的
WebappClassLoaderBase,该 tomcat 版本可从here 获得。
- 从中创建一个罐子
- 并将 jar 放入 tomcat/lib 以使其可从
Common ClassLoader 获得
配置您的WebappClassLoaderBase
在context.xml 中定义您的WebappClassLoaderBase
<Context>
...
<Loader loaderClass="my.package.MyWebappClassLoader" />
</Context>
大功告成,现在你的 webapps 将能够从 /WEB-INF/ChildApp1/lib 和 /WEB-INF/ChildApp2/lib 加载 jar 文件。
响应更新
由于您想做同样的事情,但只使用 war,您需要使用 hack 来动态添加您的 jar 文件。
您可以这样做:
实现ServletContextListener 以添加您的 jar 文件
为了在初始化上下文时动态添加您的jar 文件,您需要创建一个ServletContextListener,它将通过反射调用URLClassLoader#addURL(URL),这是一个丑陋的hack,但它可以工作。请注意,它之所以有效,是因为 Tomcat 中 webapp 的 ClassLoader 是 WebappClassLoader,它实际上是 URLClassLoader 的子类。
package my.package;
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(final ServletContextEvent sce) {
try {
// Get the method URLClassLoader#addURL(URL)
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
// Make it accessible as the method is protected
method.setAccessible(true);
String[] paths = {"/WEB-INF/ChildApp1/lib", "/WEB-INF/ChildApp2/lib"};
for (String path : paths) {
File parent = new File(sce.getServletContext().getRealPath(path));
File[] jars = parent.listFiles(
new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(".jar");
}
}
);
if (jars == null)
continue;
for (File jar : jars) {
// Add the URL to the context CL which is a URLClassLoader
// in case of Tomcat
method.invoke(
sce.getServletContext().getClassLoader(),
jar.toURI().toURL()
);
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
@Override
public void contextDestroyed(final ServletContextEvent sce) {
}
}
声明你的ServletContextListener
在您的 webapp 的 web.xml 中添加:
<listener>
<listener-class>my.package.MyServletContextListener</listener-class>
</listener>