embedded jetty doesnt clear temporary directory co

2019-06-25 04:52发布

问题:

I hava an application that uses embedded jetty and works fine.

I'm having a problem with the temporary directories generated by jetty. When an application is deployed it generates a temporary directory with the extracted war (jetty-0.0.0.0-8888-app.war-_app-any-4643933123854766078.dir), all good. But when i remove/replace this war with another version (same context), it create another temporary directory and the other one is not completely deleted. I see jetty removes all css, html files, but the web-inf/lib/*.jar are no removed.

The webAppContext.setPersistTempDirectory is set to false, i already checked.

I already tried to change the temp directory that jetty uses too.

Here's my 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);
    }
}

Here's the 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);

The server setup:

server = new Server(8888);
server.setStopAtShutdown(true);
server.setStopTimeout(5000);

handlerCollection.addHandler(contextHandlerCollection);
handlerCollection.addHandler(new DefaultHandler());

server.setHandler(handlerCollection);
server.addBean(deployManager);

I noticed that i only can manually delete the directory when i stop jetty. I think thats the only way it releases the process that uses the jars and let me completely remove.

Obs: I don't want to have to stop the server so i can remove the folders.

Thanks in advance.

回答1:

Well, find a solution. Just posting here to help anybody in need.

Here goes my files:

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.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);
            }
        }
    }
}

Set a custom classloader to the 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;
    }

}


标签: java Jetty