Если вы не разделяете модули или не используете технологии, которые разделяют компоненты в разных загрузчиках классов, таких как 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);
}
}
}