Custom ClassLoader -- third party jar packages can be loaded

package com.classloader.util;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.util.Enumeration;
import java.util.jar.Manifest;

public class NetworkClassLoader extends URLClassLoader {

    String baseUrl;

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public NetworkClassLoader(){
        this(new URL[]{});
    }

    /**
     * URL Directories ending with '/'
     *     Otherwise, jar package
     *     Its parent classloader is not specified as a system classloader
     * @param urls
     */
    public NetworkClassLoader(URL[] urls) {
        super(urls);
    }

    /**
     * As above, specify classLoader
     * @param urls
     * @param parent
     */
    public NetworkClassLoader(URL[] urls, ClassLoader parent) {
        super(urls,parent);
    }

    /**
     * Same as above, URL factory processor
     * @param urls
     * @param parent
     * @param factory
     */
    public NetworkClassLoader(URL[] urls, ClassLoader parent,
              URLStreamHandlerFactory factory) {
         super(urls,parent,factory);
    }

    /**
     * [Add baseUrl]
     * @param url
     */
    public void addURL(String url){
        URL uurl=null;
        try {
            uurl = new URL(baseUrl+url);
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        addURL(uurl);
    }

    /**
     * Add url [add baseUrl]
     */
    protected void addURL(URL url) {
        super.addURL(url);
    }

    /**
     * Return to urls
     */
    public URL[] getURLs() {
        return super.getURLs();
    }

    /**
     * Find class object
     *   Find and load the current class object from URLS above [all jars will be opened to find the specified class]
     *   (You can call findClass to get the above classes in the URL loading package)
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        return super.findClass(name);
    }

    /**
     * defineClass SecureClassLoader Defined as final method, no change allowed
     * Before using this class object, it must be resolved
     */


    /**
     * Find resource [custom relative URL find path]
     *   Find the resource with the current name from URLS above
     * This has to be rewritten because it's public haha
     */
    public URL findResource(String name) {
        URL url = null;
        try {
            url = new URL(baseUrl+name);
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return url;
    }

    /**
     * Find resource list [URL find path]
     */
    public Enumeration<URL> findResources(String name) throws IOException {
        return super.findResources(name);
    }

    /**
     * In the current ClassLoader, define a new package. The properties of the package are specified by the Manifest. The source file of the package
     */
    protected Package definePackage(String name, Manifest man, URL url)
            throws IllegalArgumentException {
        return super.definePackage(name, man, url);
    }

    /**
     * Load path permissions
     */
    protected PermissionCollection getPermissions(CodeSource codesource) {
        return super.getPermissions(codesource);
    }
}

Here's how:

NetworkClassLoader loader = new NetworkClassLoader();
    loader.setBaseUrl("file:///F: \ \ framework \ \ maven\app\jms\src\main\webapp\modules\“);

    loader.addURL("App/lib/test.jar");
    loader.addURL("App/lib/test1.jar");
    loader.addURL("App/template/view.vm");
    loader.addURL("App/config.xml");

Class resources, configuration files, etc. used by such loaders are initialized here.
Here is how to load a class resource:

Class clazz= loader.findClass("com.jvm.look.A");//Load class

Here is the load profile resource

URL uuu = loader.findResource("App/config.xml");

It should be noted that this class loader is also a parent delegation mechanism. For example, there is a class“ com.annotation.table.Test "in the parent class loader, if it has already been loaded, then if the class test.jar If it exists in, then it will not redefine the load, but use the class loaded by the parent class loader. Someone asked, how can I override the class defined in the parent class loader.
You can do the following:

Class clazz2= loader.findClass("com.annotation.table.Test");

Reload the class. I have talked about the loading sequence of the class in the previous article. For those unfamiliar, please read the above article
It may be asked that if every class is like this, I will not crash. I need to overwrite all classes defined in the parent class loader with the jar I loaded

/**
     * Overwrite the classes defined in the parent loader, and load resources with the current class loader, then all classes will execute in this loader
     * In this way, all classes in the URL are loaded through such loaders, that is to say, the definition class loader in the URL is the current class loader
     * Recommendation: try not to override the class defined by the parent loader in this way
     * (If it is overloaded, try to use this loader to load classes, so that all logic runs in this ClassLoader. Of course, SDK is still loaded from parents.)
     * You can define the interface in the SDK and provide the implementation in this JAR
     */
    public void initAllJar(){
        URL[] urls = this.getURLs();

        for(URL urll:urls){
            String url = urll.getFile();
            //Redefining all classes in this shelf package.
            if(url.endsWith("jar")){
                File jarFile  = getJarFile(url);
                JarFile jarFileTemp = null;
                try {
                    jarFileTemp = new JarFile(jarFile);
                    Enumeration<JarEntry> en = jarFileTemp.entries();
                    while (en.hasMoreElements()) {
                        JarEntry je = en.nextElement();
                        String name = je.getName();
                        if (name.endsWith(CLASS_FILE)) {
                            String className = name.substring(0, name.length()
                                    - CLASS_FILE.length());
                            findClass(pathToDot(className));
                        }
                    }

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

/**
     * The path of the jar package and the name of the jar file are specific files
     *
     * @param root
     * @param jar
     * @return
     */
    private File getJarFile(String file) {
        if (file.startsWith(PREFIX_FILE))
            file = file.substring(PREFIX_FILE.length());
        int end = file.indexOf(JAR_URL_SEPERATOR);
        if (end != (-1))
            file = file.substring(0, end);
        return new File(file);
    }

   /**
     * Path to package name [/ = = >.] / [\ \ = = >.]
     * @param s
     * @return
     */
    private String pathToDot(String s) {
        return s.replace('/', '.').replace('\\', '.');
    }

In fact, several classloaders have been provided in the JDK, which can be extended. For example, there are two versions of shelf packages in the project, all of which have the same structure, but both of them must be running. The custom class loader is useful.

To: http://a123159521.iteye.com/blog/1095264

Tags: Java xml SDK Maven

Posted on Wed, 20 May 2020 08:52:11 -0700 by bumbar