Загрузчик классов в Java - PullRequest
       33

Загрузчик классов в Java

0 голосов
/ 11 февраля 2019

Как я могу сканировать определенный файл JAR вместо сканирования полного пути к классу Java при использовании загрузчика классов?

Например: у меня есть Jar1, Jar2, Jar3, Jar4 в пути к классам, но я хочу сканировать толькоJar4 при использовании загрузчика классов для сканирования определенного класса.

1 Ответ

0 голосов
/ 12 февраля 2019

Если вы не разделяете модули или не используете технологии, которые разделяют компоненты в разных загрузчиках классов, таких как OSGI, вы не сможете сделать это без какой-либо структуры или нового экземпляра загрузчика классов.

Допустим, вы используетеЗагрузчик классов из контекста, в котором вы находитесь:

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packageName.replace('.', '/');
        Enumeration resources = classLoader.getResources(path);
        List dirs = new ArrayList();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        ArrayList classes = new ArrayList();
        for (File directory : dirs) {
            classes.addAll(findClasses(directory, packageName));
        }
        return classes.toArray(new Class[classes.size()]);

Однако это слишком сложно, и иногда у вас нет такой структуры.Если вы получаете новый загрузчик классов, вы можете указать ему сканировать родительский загрузчик классов последним, например, и сделать что-то вроде:

ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(
        Arrays.asList(new File("a.jar").toURI().toURL()));
Class<?> carClass = classLoader.loadClass("com.acme.Car");
Vehicle someCar = (Vehicle) carClass.newInstance();

В этом примере можно отметить кое-что важное: класс идентифицируется с загрузчиком классов какфактор.Поэтому нельзя иметь:

com.acme.Car carClass = classLoader.loadClass("com.acme.Car");

Поскольку первый com.acme.Car и второй загружаются из разных загрузчиков классов и, следовательно, являются разными классами.

Этот пример взят из принятых в настоящее времяответ на: Как мне создать ClassLoader для родительского последнего / дочернего первого в Java, или Как переопределить старую версию Xerces, которая уже была загружена в родительский CL?

/**
 * A parent-last classloader that will try the child classloader first and then the parent.
 * This takes a fair bit of doing because java really prefers parent-first.
 * 
 * For those not familiar with class loading trickery, be wary
 */
private static class ParentLastURLClassLoader extends ClassLoader 
{
    private ChildURLClassLoader childClassLoader;

    /**
     * This class allows me to call findClass on a classloader
     */
    private static class FindClassClassLoader extends ClassLoader
    {
        public FindClassClassLoader(ClassLoader parent)
        {
            super(parent);
        }

        @Override
        public Class<?> findClass(String name) throws ClassNotFoundException
        {
            return super.findClass(name);
        }
    }

    /**
     * This class delegates (child then parent) for the findClass method for a URLClassLoader.
     * We need this because findClass is protected in URLClassLoader
     */
    private static class ChildURLClassLoader extends URLClassLoader
    {
        private FindClassClassLoader realParent;

        public ChildURLClassLoader( URL[] urls, FindClassClassLoader realParent )
        {
            super(urls, null);

            this.realParent = realParent;
        }

        @Override
        public Class<?> findClass(String name) throws ClassNotFoundException
        {
            try
            {
                // first try to use the URLClassLoader findClass
                return super.findClass(name);
            }
            catch( ClassNotFoundException e )
            {
                // if that fails, we ask our real parent classloader to load the class (we give up)
                return realParent.loadClass(name);
            }
        }
    }

    public ParentLastURLClassLoader(List<URL> classpath)
    {
        super(Thread.currentThread().getContextClassLoader());

        URL[] urls = classpath.toArray(new URL[classpath.size()]);

        childClassLoader = new ChildURLClassLoader( urls, new FindClassClassLoader(this.getParent()) );
    }

    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
    {
        try
        {
            // first we try to find a class inside the child classloader
            return childClassLoader.findClass(name);
        }
        catch( ClassNotFoundException e )
        {
            // didn't find it, try the parent
            return super.loadClass(name, resolve);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...