Мне нужно получить имена всех пакетов Java, загруженных JVM. Это нужно для отображения обозревателя пакетов, подобного тем, которые можно найти в IDE. Я могу получить список пакетов текущего загрузчика классов и его предков, обратившись к защищенному полю «пакеты» класса ClassLoader. Но я не могу загрузить пакеты другими веб-приложениями, поскольку у них есть свои собственные загрузчики классов. Я тестирую это на сервере Weblogic
Как получить список всех имен пакетов, загруженных JVM
Ответы (4)
Ожидаемое поведение модели безопасности Weblogic заключается в том, что у вас не будет доступа к загрузчикам классов других веб-приложений. Это не то, что вы сможете обойти - см. эту статью для получения дополнительной информации.
Вам нужно пройтись по дереву загрузчиков классов, используя getParent()
, найти все классы, которые расширяют ClassLoader, найти все текущие экземпляры (здесь должен помочь API отладки). Но это, вероятно, не сработает для веб-серверов из-за политики безопасности (веб-приложениям не разрешено просматривать друг друга).
Для Tomcat есть возможность регистрировать все классы по мере их загрузки. Это довольно сильно замедляет работу сервера, но это может быть вариант на сервере разработки.
Тем не менее, мне очень любопытно, зачем вам это нужно. Самым простым решением было бы перечислить все файлы JAR, которые приносит ваше приложение, с jar tvf
и удалить последнюю часть пути (файл класса).
Единственный способ, которым я могу это сделать, - это изменить каждое веб-приложение, чтобы вы могли отправлять каждому запрос на информацию о загруженном классе. Затем вы можете создать новое веб-приложение, которое объединяет ответы существующих веб-приложений для отображения.
Если вам не нужна эта информация в каком-то приятном пользовательском интерфейсе, тогда у Sun JVM есть несколько опций -XX vm, которые покажут вам, что происходит с загрузкой классов.
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
Я не очень хорошо знаком с JRockit, но был бы удивлен, если бы у него не было подобных опций.
Хорошо, мне удалось заставить это работать на Weblogic. Моя цель снова состояла в том, чтобы получить имена пакетов Java во всех приложениях, развернутых на данном сервере WebLogic. Почему? У меня были свои причины :)
Сначала вам нужно получить информацию о расположении файлов ear, war или jar всех развернутых приложений. Для этого мы получаем MBean-компоненты AppDeployment из WebLogic и выполняем итерацию, как показано ниже.
Set<ObjectName> set = utils.getConfigMBeansByType("AppDeployment");
for (ObjectName objectName : set) {
String name = objectName.getKeyProperty("Name");
if (!appCache.contains(name)) {
//System.out.println("Config bean: " + objectName);
Object path = utils.getPropertyValue(objectName,
"AbsoluteSourcePath");
//System.out.println("Path: " + path);
if(path != null){
PackageFinder finder = new PackageFinder();
packages.addAll(finder.findPackages(path.toString()));
}
appCache.add(name);
}
}
В приведенном выше коде мы получаем путь к файлу war, ear, jar или взорванной папке и передаем его методу findPakages класса PackageFinder, который выполняет всю работу.
public Set<String> findPackages(String path){
File file = new File(path);
if(file.exists() && file.isFile()){
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
if(path.toLowerCase().endsWith(".war")){
processWar(in);
}else if(path.toLowerCase().endsWith(".ear")){
processEar(in);
}/*
Rest of the method body removed, I guess you get the idea
*/
return packageNames;
}
public void processJar(InputStream in){
ZipInputStream zin = null;
try {
zin = new ZipInputStream(in);
ZipEntry entry;
while((entry = zin.getNextEntry()) != null){
if(entry.getName().endsWith(".class")){
addPackage(entry.getName());
}
}
} catch (Exception e) {
}
}