URLClassLoader carga la clase con el mismo nombre

prefacio

           Como el cargador de clases más utilizado y ampliamente utilizado, URLClassLoader desempeña un papel fundamental en el mundo de Java. Como codificador, es necesario tener una cierta comprensión de sus funciones y usos para moverse libremente en el mundo de Java. Como elemento central en Java, el cargador de clases siempre puede encontrar una solución cuando se encuentra con algunas enfermedades intratables. Creo que los amigos a menudo se encuentran con el problema de los conflictos de paquetes jar, en este caso, la solución general es eliminar otras versiones de paquetes jar y finalmente mantener solo una versión. Entonces, ¿pueden coexistir varias versiones? La respuesta es sí. El problema aún radica en el cargador de clases.Debido a la existencia del mecanismo de delegación principal, para los paquetes jar que contienen el mismo nombre de clase, la instancia de clase solo seleccionará el paquete jar que se carga primero, y este último será ignorado. Si desea lograr el propósito de la coexistencia de múltiples versiones de paquetes jar, solo puede permitir que estos paquetes jar sean cargados por diferentes cargadores de clases.

1. Cargador de clases del sistema AppClassLoader y URLClassLoader

       Generalmente, el cargador de clases del sistema es AppClassLoader, por supuesto, también puede pasar la opción jvm Djava.system.class.loader. La clase AppClassLoader hereda de la clase URLClassLoader. La ruta cargada por URLClassLoader incluye el directorio de archivos , el paquete jar y la ruta de la red. En la mayoría de los casos, usamos los dos primeros.

       Generalmente, la carga de la ruta se inicializa especificando la matriz de URL en el constructor de clases de URLClassLoader. Por supuesto, la forma de reflexión también se puede usar para cargar dinámicamente la ruta. También hay dos métodos de reflexión, uno es cargar a través del método addURL de la variable miembro ucp de URLClassLoader, y el otro es cargar directamente a través de addURL de la propia clase URLClassLoader. AppClassLoader también se puede cargar a través del método appendToClassPathForInstrumentation(String)

Por supuesto, la esencia es llamar a addURL de URLClassLoader para cargar.

2. Cómo cargar la clase con el mismo nombre

       1. Cree una subclase de la clase URLClassLoader, reescriba el método loadClass y mantenga una variable de la clase de colección.

Cuando el nombre de la clase que se va a cargar ya existe en la variable de colección, se omite el paso de cargar desde el cargador principal.

             Debido a que todos los cargadores de clases heredan de ClassLoader, la siguiente es la implementación de su método loadClass

      

      Cuando la carga falla en el cargador principal, irá al método findClass, por lo que podemos eliminar el proceso de carga del cargador principal en el método loadClass sobrecargado.

El código completo de la clase MyURLClassLoader es el siguiente

paquete com.suntown.loader; 

importar java.io.Archivo; 
importar java.io.IOException; 
importar java.net.URL; 
importar java.net.URLClassLoader; 
importar java.net.URLStreamHandlerFactory; 
importar java.util.*; 
importar java.util.jar.JarEntry; 
importar java.util.jar.JarFile; 

public abstract class MyURLClassLoader extiende URLClassLoader { 
    public MyURLClassLoader(URL[] urls, ClassLoader classLoader) { 
        super(urls, classLoader); 

        filtro (URL); 
    } 

    public MyURLClassLoader(URL[] urls) { 
        super(urls); 

        filtro (URL); 
    }

    public MyURLClassLoader(URL[] urls, ClassLoader classLoader, URLStreamHandlerFactory urlStreamHandlerFactory) { 
        super(urls, classLoader, urlStreamHandlerFactory); 

        filtro (URL); 
    } 

    protected void addURL(URL url) { 
        super.addURL(url); 
        filtro (url); 
    } 

    private Set<String> classNameSet = new HashSet<String>(); 

    público abstracto booleano isOverrideURL (URL url); 

    filtro anulado privado (URL url){ 
        if(isOverrideURL(url)){ 
            try{ 
                File f = new File(url.getPath()); 
                if(f.exists()){ 
                    JarFile jarFile = new JarFile(f.getAbsolutePath());
                    Enumeración<JarEntry> et = jarFile.entries(); 
                    while (et.hasMoreElements()) { 
                        JarEntry ele = et.nextElement(); 
                        if (ele.getName().endsWith(".class")) { 
                            String nombre = ele.getName().substring(0, ele.getName().length() - 6).replace("/", " ."); 
                            classNameSet.add(nombre); 
                        } 
                    } 
                } 
            }catch(IOException e){ 
                e.printStackTrace(); 
            } 
        } 
    } 

    filtro anulado privado (URL[] urls){ 
        for(URL url : urls){ 
            filtro (url); 
        } 
    }

    public Class loadClass(String name) throws ClassNotFoundException { 
        if(classNameSet.contains(name)){ 
            return super.findClass(name); 
        }else{ 
            return super.loadClass(nombre); 
        } 
} 
    }

3. Verificación de la operación

Use AppClassLoader, URLClassLoader y MyURLClassLoader para cargar una clase en el mismo paquete jar respectivamente

E imprima el ClassLoader al que pertenece la clase respectivamente.

El código de prueba es el siguiente

        

cargador de paquetes; 

importar sun.misc.URLClassPath; 

importar java.io.Archivo; 
importar java.lang.reflect.Field; 
importar java.lang.reflect.InvocationTargetException; 
importar java.lang.reflect.Method; 
importar java.net.MalformedURLException; 
importar java.net.URL; 
importar java.net.URLClassLoader; 

clase pública LoaderTest{ 
    public static void main(String[] args) lanza NoSuchFieldException, IllegalAccessException, MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { 
        URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
        cargador de usuario URLClassLoader = nuevo URLClassLoader(nueva URL[]{});
        URLClassLoader myloader = new MyURLClassLoader(nueva URL[]{}) { 
            @Override 
            public boolean isOverrideURL(URL url) { 
                return true; 
            } 
        }; 

        Método mdAddURL = URLClassLoader.class.getDeclaredMethod("addURL",java.net.URL.class); 
        mdAddURL.setAccesible(verdadero); 

        URL url = nuevo archivo ("f:\\git\\test\\ojdbc6.jar").toURI().toURL(); 
        mdAddURL.invoke(sysloader,nuevo Objeto[]{url}); 
        mdAddURL.invoke(userloader,nuevo Objeto[]{url}); 
        mdAddURL.invoke(myloader,nuevo Objeto[]{url}); 

        Clase c1 = sysloader.loadClass("oracle.sql.CHAR"); 
        System.out.println(c1.getClassLoader());

        Clase c2 = cargador de usuario.loadClass("oracle.sql.CHAR");
        System.out.println(c2.getClassLoader()); 

        Clase c3 = myloader.loadClass("oracle.sql.CHAR"); 
        System.out.println(c3.getClassLoader()); 
    } 
}

El resultado de la operación es el siguiente

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_38526093/article/details/128986854
Recomendado
Clasificación