嵌入式码头不完全清除临时目录(保留 lib/*.jar)
embedded jetty doesnt clear temporary directory completely (keeps lib/*.jar)
我有一个使用嵌入式码头并且工作正常的应用程序。
我对码头生成的临时目录有疑问。
部署应用程序时,它会生成一个临时目录,其中包含提取的 war (jetty-0.0.0.0-8888-app.war-_app-any-4643933123854766078.dir),一切正常。
但是当我 remove/replace 这个 war 与另一个版本(相同的上下文)时,它会创建另一个临时目录并且另一个不会被完全删除。我看到码头删除了所有 css、html 文件,但是 web-inf/lib/*.jar 没有被删除。
webAppContext.setPersistTempDirectory
设置为false,我已经检查过了。
我已经尝试过更改 jetty 使用的临时目录。
这是我的 WebAppProvider:
WebAppProvider webAppProvider = new WebAppProvider();
webAppProvider.setMonitoredDirName("webapps");
webAppProvider.setScanInterval(1);
webAppProvider.setExtractWars(true);
webAppProvider.setDefaultsDescriptor("webdefault.xml");
webAppProvider.setTempDir(new File("work"));
String webDefault = Thread.currentThread().getContextClassLoader().getResource("webdefault.xml").getPath();
if (webDefault != null) {
File f = new File(webDefault);
if (f.exists() && !f.isDirectory()) {
webAppProvider.setDefaultsDescriptor(webDefault);
}
}
这是 DeploymentManager:
DeploymentManager deploymentManager = new DeploymentManager();
deploymentManager.setContexts(contextHandlerCollection);
deploymentManager.setContextAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\.jar$|.*/javax.servlet.jsp.jstl-.*\.jar$|.*/org.apache.taglibs.taglibs-standard-impl-.*\.jar$");
deploymentManager.addAppProvider(webAppProvider);
服务器设置:
server = new Server(8888);
server.setStopAtShutdown(true);
server.setStopTimeout(5000);
handlerCollection.addHandler(contextHandlerCollection);
handlerCollection.addHandler(new DefaultHandler());
server.setHandler(handlerCollection);
server.addBean(deployManager);
我注意到我只能在停止码头时手动删除目录。我认为这是释放使用 jars 的进程并让我完全删除的唯一方法。
Obs:我不想停止服务器以便删除文件夹。
提前致谢。
好吧,我找到了解决办法。只是张贴在这里以帮助有需要的人。
这是我的文件:
部署管理器:
DeploymentManager deploymentManager = new DeploymentManager();
deploymentManager.setContexts(contextHandlerCollection);
deploymentManager.setContextAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\.jar$|.*/javax.servlet.jsp.jstl-.*\.jar$|.*/org.apache.taglibs.taglibs-standard-impl-.*\.jar$");
deploymentManager.addLifeCycleBinding(new StandardStarter());
deploymentManager.addLifeCycleBinding(new StandardStopperCustom());
deploymentManager.addLifeCycleBinding(new StandardDeployer());
deploymentManager.addLifeCycleBinding(new StandardUndeployer());
deploymentManager.setUseStandardBindings(false);
deploymentManager.addAppProvider(webAppProvider);
WebAppProvider:
WebAppProviderCustom webAppProvider = new WebAppProviderCustom();
webAppProvider.setMonitoredDirName("webapps");
webAppProvider.setScanInterval(1);
webAppProvider.setExtractWars(true);
webAppProvider.setDefaultsDescriptor("webdefault.xml");
webAppProvider.setTempDir(new File("work"));
String webDefault = Thread.currentThread().getContextClassLoader().getResource("webdefault.xml").getPath();
if (webDefault != null) {
File f = new File(webDefault);
if (f.exists() && !f.isDirectory()) {
webAppProvider.setDefaultsDescriptor(webDefault);
}
}
StopperCustom:
public class StandardStopperCustom extends StandardStopper {
@Override
public void processBinding(Node node, App app) throws Exception {
ContextHandler handler;
try {
handler = app.getContextHandler();
if (handler instanceof WebAppContext) {
WebAppContext webapp = (WebAppContext) handler;
File tempDirectory = (File) webapp.getAttribute("javax.servlet.context.tempdir");
String baseDirectory = tempDirectory.getName();
if (webapp.getClassLoader() instanceof WebAppClassLoaderCustom && !baseDirectory.isEmpty()) {
WebAppClassLoaderCustom classLoader = (WebAppClassLoaderCustom) webapp.getClassLoader();
super.processBinding(node, app);
classLoader.close();
cleanUpTempDirectory(baseDirectory);
}
} else {
super.processBinding(node, app);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
public void cleanUpTempDirectory(String tempDirectory) {
File work = new File(Constantes.workDirectory);
File[] jettyFolders = work.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.equalsIgnoreCase(tempDirectory)) {
return true;
}
return false;
}
});
if (jettyFolders != null && jettyFolders.length > 0) {
for (File file : jettyFolders) {
IO.delete(file);
}
}
}
}
将自定义类加载器设置为 webappcontext:webAppContext.setClassLoader(new WebAppClassLoaderCustom(webAppContext));
WebAppClassLoaderCustom:
public class WebAppClassLoaderCustom extends WebAppClassLoader {
private HashSet<String> jarFileToClose = new HashSet<String>();
public WebAppClassLoaderCustom(Context context) throws IOException {
super(context);
}
public WebAppClassLoaderCustom(ClassLoader parent, Context context) throws IOException {
super(parent, context);
}
@Override
public void close() {
System.out.println("Closing ClassLoader.");
jarFileToClose.clear();
closeClassLoader(this);
// finalizeNativeLibs(this);
cleanupJarFileFactory();
try {
super.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
private boolean closeClassLoader(ClassLoader cl) {
boolean res = false;
if (cl == null) {
return res;
}
Class classURLClassLoader = URLClassLoader.class;
Field f = null;
try {
f = classURLClassLoader.getDeclaredField("ucp");
} catch (NoSuchFieldException e1) {
// ignore
}
if (f != null) {
f.setAccessible(true);
Object obj = null;
try {
obj = f.get(cl);
} catch (IllegalAccessException e1) {
// ignore
}
if (obj != null) {
final Object ucp = obj;
f = null;
try {
f = ucp.getClass().getDeclaredField("loaders");
} catch (NoSuchFieldException e1) {
// ignore
}
if (f != null) {
f.setAccessible(true);
ArrayList loaders = null;
try {
loaders = (ArrayList) f.get(ucp);
res = true;
} catch (IllegalAccessException e1) {
// ignore
}
for (int i = 0; loaders != null && i < loaders.size(); i++) {
obj = loaders.get(i);
f = null;
try {
f = obj.getClass().getDeclaredField("jar");
} catch (NoSuchFieldException e) {
// ignore
}
if (f != null) {
f.setAccessible(true);
try {
obj = f.get(obj);
} catch (IllegalAccessException e1) {
// ignore
}
if (obj instanceof JarFile) {
final JarFile jarFile = (JarFile) obj;
jarFileToClose.add(jarFile.getName());
try {
jarFile.close();
} catch (IOException e) {
// ignore
}
}
}
}
}
}
}
return res;
}
@SuppressWarnings("rawtypes")
private boolean finalizeNativeLibs(ClassLoader cl) {
boolean res = false;
Class classClassLoader = ClassLoader.class;
java.lang.reflect.Field nativeLibraries = null;
try {
nativeLibraries = classClassLoader.getDeclaredField("nativeLibraries");
} catch (NoSuchFieldException e1) {
// ignore
}
if (nativeLibraries == null) {
return res;
}
nativeLibraries.setAccessible(true);
Object obj = null;
try {
obj = nativeLibraries.get(cl);
} catch (IllegalAccessException e1) {
// ignore
}
if (!(obj instanceof Vector)) {
return res;
}
res = true;
Vector java_lang_ClassLoader_NativeLibrary = (Vector) obj;
for (Object lib : java_lang_ClassLoader_NativeLibrary) {
java.lang.reflect.Method finalize = null;
try {
finalize = lib.getClass().getDeclaredMethod("finalize", new Class[0]);
} catch (NoSuchMethodException e) {
// ignore
}
if (finalize != null) {
finalize.setAccessible(true);
try {
finalize.invoke(lib, new Object[0]);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
// ignore
}
}
}
return res;
}
@SuppressWarnings("rawtypes")
private boolean cleanupJarFileFactory() {
boolean res = false;
Class classJarURLConnection = null;
try {
classJarURLConnection = Class.forName("sun.net.www.protocol.jar.JarURLConnection");
} catch (ClassNotFoundException e) {
// ignore
}
if (classJarURLConnection == null) {
return res;
}
Field f = null;
try {
f = classJarURLConnection.getDeclaredField("factory");
} catch (NoSuchFieldException e) {
// ignore
}
if (f == null) {
return res;
}
f.setAccessible(true);
Object obj = null;
try {
obj = f.get(null);
} catch (IllegalAccessException e) {
// ignore
}
if (obj == null) {
return res;
}
Class classJarFileFactory = obj.getClass();
//
HashMap fileCache = null;
try {
f = classJarFileFactory.getDeclaredField("fileCache");
f.setAccessible(true);
obj = f.get(null);
if (obj instanceof HashMap) {
fileCache = (HashMap) obj;
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
// ignore
}
HashMap urlCache = null;
try {
f = classJarFileFactory.getDeclaredField("urlCache");
f.setAccessible(true);
obj = f.get(null);
if (obj instanceof HashMap) {
urlCache = (HashMap) obj;
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
// ignore
}
if (urlCache != null) {
HashMap urlCacheTmp = (HashMap) urlCache.clone();
Iterator it = urlCacheTmp.keySet().iterator();
while (it.hasNext()) {
obj = it.next();
if (!(obj instanceof JarFile)) {
continue;
}
JarFile jarFile = (JarFile) obj;
if (jarFileToClose.contains(jarFile.getName())) {
try {
jarFile.close();
} catch (IOException e) {
// ignore
}
if (fileCache != null) {
fileCache.remove(urlCache.get(jarFile));
}
urlCache.remove(jarFile);
}
}
res = true;
} else if (fileCache != null) {
// urlCache := null
HashMap fileCacheTmp = (HashMap) fileCache.clone();
Iterator it = fileCacheTmp.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
obj = fileCache.get(key);
if (!(obj instanceof JarFile)) {
continue;
}
JarFile jarFile = (JarFile) obj;
if (jarFileToClose.contains(jarFile.getName())) {
try {
jarFile.close();
} catch (IOException e) {
// ignore
}
fileCache.remove(key);
}
}
res = true;
}
jarFileToClose.clear();
return res;
}
}
我有一个使用嵌入式码头并且工作正常的应用程序。
我对码头生成的临时目录有疑问。 部署应用程序时,它会生成一个临时目录,其中包含提取的 war (jetty-0.0.0.0-8888-app.war-_app-any-4643933123854766078.dir),一切正常。 但是当我 remove/replace 这个 war 与另一个版本(相同的上下文)时,它会创建另一个临时目录并且另一个不会被完全删除。我看到码头删除了所有 css、html 文件,但是 web-inf/lib/*.jar 没有被删除。
webAppContext.setPersistTempDirectory
设置为false,我已经检查过了。
我已经尝试过更改 jetty 使用的临时目录。
这是我的 WebAppProvider:
WebAppProvider webAppProvider = new WebAppProvider();
webAppProvider.setMonitoredDirName("webapps");
webAppProvider.setScanInterval(1);
webAppProvider.setExtractWars(true);
webAppProvider.setDefaultsDescriptor("webdefault.xml");
webAppProvider.setTempDir(new File("work"));
String webDefault = Thread.currentThread().getContextClassLoader().getResource("webdefault.xml").getPath();
if (webDefault != null) {
File f = new File(webDefault);
if (f.exists() && !f.isDirectory()) {
webAppProvider.setDefaultsDescriptor(webDefault);
}
}
这是 DeploymentManager:
DeploymentManager deploymentManager = new DeploymentManager();
deploymentManager.setContexts(contextHandlerCollection);
deploymentManager.setContextAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\.jar$|.*/javax.servlet.jsp.jstl-.*\.jar$|.*/org.apache.taglibs.taglibs-standard-impl-.*\.jar$");
deploymentManager.addAppProvider(webAppProvider);
服务器设置:
server = new Server(8888);
server.setStopAtShutdown(true);
server.setStopTimeout(5000);
handlerCollection.addHandler(contextHandlerCollection);
handlerCollection.addHandler(new DefaultHandler());
server.setHandler(handlerCollection);
server.addBean(deployManager);
我注意到我只能在停止码头时手动删除目录。我认为这是释放使用 jars 的进程并让我完全删除的唯一方法。
Obs:我不想停止服务器以便删除文件夹。
提前致谢。
好吧,我找到了解决办法。只是张贴在这里以帮助有需要的人。
这是我的文件:
部署管理器:
DeploymentManager deploymentManager = new DeploymentManager();
deploymentManager.setContexts(contextHandlerCollection);
deploymentManager.setContextAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\.jar$|.*/javax.servlet.jsp.jstl-.*\.jar$|.*/org.apache.taglibs.taglibs-standard-impl-.*\.jar$");
deploymentManager.addLifeCycleBinding(new StandardStarter());
deploymentManager.addLifeCycleBinding(new StandardStopperCustom());
deploymentManager.addLifeCycleBinding(new StandardDeployer());
deploymentManager.addLifeCycleBinding(new StandardUndeployer());
deploymentManager.setUseStandardBindings(false);
deploymentManager.addAppProvider(webAppProvider);
WebAppProvider:
WebAppProviderCustom webAppProvider = new WebAppProviderCustom();
webAppProvider.setMonitoredDirName("webapps");
webAppProvider.setScanInterval(1);
webAppProvider.setExtractWars(true);
webAppProvider.setDefaultsDescriptor("webdefault.xml");
webAppProvider.setTempDir(new File("work"));
String webDefault = Thread.currentThread().getContextClassLoader().getResource("webdefault.xml").getPath();
if (webDefault != null) {
File f = new File(webDefault);
if (f.exists() && !f.isDirectory()) {
webAppProvider.setDefaultsDescriptor(webDefault);
}
}
StopperCustom:
public class StandardStopperCustom extends StandardStopper {
@Override
public void processBinding(Node node, App app) throws Exception {
ContextHandler handler;
try {
handler = app.getContextHandler();
if (handler instanceof WebAppContext) {
WebAppContext webapp = (WebAppContext) handler;
File tempDirectory = (File) webapp.getAttribute("javax.servlet.context.tempdir");
String baseDirectory = tempDirectory.getName();
if (webapp.getClassLoader() instanceof WebAppClassLoaderCustom && !baseDirectory.isEmpty()) {
WebAppClassLoaderCustom classLoader = (WebAppClassLoaderCustom) webapp.getClassLoader();
super.processBinding(node, app);
classLoader.close();
cleanUpTempDirectory(baseDirectory);
}
} else {
super.processBinding(node, app);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
public void cleanUpTempDirectory(String tempDirectory) {
File work = new File(Constantes.workDirectory);
File[] jettyFolders = work.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.equalsIgnoreCase(tempDirectory)) {
return true;
}
return false;
}
});
if (jettyFolders != null && jettyFolders.length > 0) {
for (File file : jettyFolders) {
IO.delete(file);
}
}
}
}
将自定义类加载器设置为 webappcontext:webAppContext.setClassLoader(new WebAppClassLoaderCustom(webAppContext));
WebAppClassLoaderCustom:
public class WebAppClassLoaderCustom extends WebAppClassLoader {
private HashSet<String> jarFileToClose = new HashSet<String>();
public WebAppClassLoaderCustom(Context context) throws IOException {
super(context);
}
public WebAppClassLoaderCustom(ClassLoader parent, Context context) throws IOException {
super(parent, context);
}
@Override
public void close() {
System.out.println("Closing ClassLoader.");
jarFileToClose.clear();
closeClassLoader(this);
// finalizeNativeLibs(this);
cleanupJarFileFactory();
try {
super.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
private boolean closeClassLoader(ClassLoader cl) {
boolean res = false;
if (cl == null) {
return res;
}
Class classURLClassLoader = URLClassLoader.class;
Field f = null;
try {
f = classURLClassLoader.getDeclaredField("ucp");
} catch (NoSuchFieldException e1) {
// ignore
}
if (f != null) {
f.setAccessible(true);
Object obj = null;
try {
obj = f.get(cl);
} catch (IllegalAccessException e1) {
// ignore
}
if (obj != null) {
final Object ucp = obj;
f = null;
try {
f = ucp.getClass().getDeclaredField("loaders");
} catch (NoSuchFieldException e1) {
// ignore
}
if (f != null) {
f.setAccessible(true);
ArrayList loaders = null;
try {
loaders = (ArrayList) f.get(ucp);
res = true;
} catch (IllegalAccessException e1) {
// ignore
}
for (int i = 0; loaders != null && i < loaders.size(); i++) {
obj = loaders.get(i);
f = null;
try {
f = obj.getClass().getDeclaredField("jar");
} catch (NoSuchFieldException e) {
// ignore
}
if (f != null) {
f.setAccessible(true);
try {
obj = f.get(obj);
} catch (IllegalAccessException e1) {
// ignore
}
if (obj instanceof JarFile) {
final JarFile jarFile = (JarFile) obj;
jarFileToClose.add(jarFile.getName());
try {
jarFile.close();
} catch (IOException e) {
// ignore
}
}
}
}
}
}
}
return res;
}
@SuppressWarnings("rawtypes")
private boolean finalizeNativeLibs(ClassLoader cl) {
boolean res = false;
Class classClassLoader = ClassLoader.class;
java.lang.reflect.Field nativeLibraries = null;
try {
nativeLibraries = classClassLoader.getDeclaredField("nativeLibraries");
} catch (NoSuchFieldException e1) {
// ignore
}
if (nativeLibraries == null) {
return res;
}
nativeLibraries.setAccessible(true);
Object obj = null;
try {
obj = nativeLibraries.get(cl);
} catch (IllegalAccessException e1) {
// ignore
}
if (!(obj instanceof Vector)) {
return res;
}
res = true;
Vector java_lang_ClassLoader_NativeLibrary = (Vector) obj;
for (Object lib : java_lang_ClassLoader_NativeLibrary) {
java.lang.reflect.Method finalize = null;
try {
finalize = lib.getClass().getDeclaredMethod("finalize", new Class[0]);
} catch (NoSuchMethodException e) {
// ignore
}
if (finalize != null) {
finalize.setAccessible(true);
try {
finalize.invoke(lib, new Object[0]);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
// ignore
}
}
}
return res;
}
@SuppressWarnings("rawtypes")
private boolean cleanupJarFileFactory() {
boolean res = false;
Class classJarURLConnection = null;
try {
classJarURLConnection = Class.forName("sun.net.www.protocol.jar.JarURLConnection");
} catch (ClassNotFoundException e) {
// ignore
}
if (classJarURLConnection == null) {
return res;
}
Field f = null;
try {
f = classJarURLConnection.getDeclaredField("factory");
} catch (NoSuchFieldException e) {
// ignore
}
if (f == null) {
return res;
}
f.setAccessible(true);
Object obj = null;
try {
obj = f.get(null);
} catch (IllegalAccessException e) {
// ignore
}
if (obj == null) {
return res;
}
Class classJarFileFactory = obj.getClass();
//
HashMap fileCache = null;
try {
f = classJarFileFactory.getDeclaredField("fileCache");
f.setAccessible(true);
obj = f.get(null);
if (obj instanceof HashMap) {
fileCache = (HashMap) obj;
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
// ignore
}
HashMap urlCache = null;
try {
f = classJarFileFactory.getDeclaredField("urlCache");
f.setAccessible(true);
obj = f.get(null);
if (obj instanceof HashMap) {
urlCache = (HashMap) obj;
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
// ignore
}
if (urlCache != null) {
HashMap urlCacheTmp = (HashMap) urlCache.clone();
Iterator it = urlCacheTmp.keySet().iterator();
while (it.hasNext()) {
obj = it.next();
if (!(obj instanceof JarFile)) {
continue;
}
JarFile jarFile = (JarFile) obj;
if (jarFileToClose.contains(jarFile.getName())) {
try {
jarFile.close();
} catch (IOException e) {
// ignore
}
if (fileCache != null) {
fileCache.remove(urlCache.get(jarFile));
}
urlCache.remove(jarFile);
}
}
res = true;
} else if (fileCache != null) {
// urlCache := null
HashMap fileCacheTmp = (HashMap) fileCache.clone();
Iterator it = fileCacheTmp.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
obj = fileCache.get(key);
if (!(obj instanceof JarFile)) {
continue;
}
JarFile jarFile = (JarFile) obj;
if (jarFileToClose.contains(jarFile.getName())) {
try {
jarFile.close();
} catch (IOException e) {
// ignore
}
fileCache.remove(key);
}
}
res = true;
}
jarFileToClose.clear();
return res;
}
}