2015-01-21 4 views
2

Есть ли (pref portable) способ проверить, есть ли JVM указан с -javaagent?Проверьте, не загружен ли аксессуар (или какой-либо javaagent)

В частности, мне интересно узнать, загружен ли ткацкий станок с загрузкой аксессуаров или нет. (Я пытаюсь предоставить полезную ошибку msg в случае неправильного запуска).

ответ

10

Следующий код показывает

  • способ определить, какие -javaagent:... аргументы виртуальной машины Java,
  • способ проверить, если плетение агент класса точки входа AspectJ (которая упоминается в явной записи Premain-Class: из aspectjweaver .jar).

Бывший просто доказывает, что аргумент был указан в командной строке, а не то, что агент был фактически найден и запущен.

Последний просто доказывает, что ткач доступен на пути к классам, а не то, что он фактически был запущен как агент. Комбинация обоих должна дать вам довольно большую уверенность в том, что агент действительно активен.

package de.scrum_master.app; 

import java.lang.management.ManagementFactory; 
import java.lang.management.RuntimeMXBean; 
import java.util.List; 

public class Application { 
    public static void main(String[] args) { 
     RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); 
     List<String> arguments = runtimeMxBean.getInputArguments(); 
     for (String argument : arguments) { 
      if (argument.startsWith("-javaagent:")) 
       System.out.println(argument); 
     } 
     try { 
      Class.forName("org.aspectj.weaver.loadtime.Agent"); 
     } catch (ClassNotFoundException e) { 
      System.err.println("WARNING: AspectJ weaving agent not loaded"); 
     } 
    } 
} 

Вы можете также найти вопрос Starting a Java agent after program start и некоторые из его ответов полезных.


Update:

Хорошо, вот это сочетание моего собственного решения и ваша, но тот, который на самом деле работает, даже если ткач недоступен, что очень важно, потому что это то, что вы хотите проверить в первую очередь:

public static boolean isAspectJAgentLoaded() { 
    try { 
     Class<?> agentClass = Class.forName("org.aspectj.weaver.loadtime.Agent"); 
     Method method = agentClass.getMethod("getInstrumentation"); 
     method.invoke(null); 
    } catch (Exception e) { 
     //System.out.println(e); 
     return false; 
    } 
    return true; 
} 

Update 2:

После некоторого обсуждения с OP Bacar я решил предложить решение, которое не используют отражения, но ловит NoClassDefError вместо:

public static boolean isAspectJAgentLoaded() { 
    try { 
     org.aspectj.weaver.loadtime.Agent.getInstrumentation(); 
    } catch (NoClassDefFoundError | UnsupportedOperationException e) { 
     System.out.println(e); 
     return false; 
    } 
    return true; 
} 

Теперь оба основных типов ошибок

  • ткачество агент доступно в пути к классам, но инструментарий не был инициирован, потому что aspectjweaver.jar не был запущен как агент Java,
  • агент aspectjweaver.jar не на пути к классам на всех и класс org.aspectj.weaver.loadtime.Agent, таким образом, отсутствует

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

Возможные консольные выходы для двух случаев:

  • java.lang.UnsupportedOperationException: Java 5 was not started with preMain -javaagent for AspectJ
  • java.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent
+0

Спасибо. Вопрос, которым вы ссылались, был моей начальной отправной точкой (я предпочитаю загружать автоматически вместо ошибки), но для динамической загрузки требуется tools.jar, и я не нашел хорошего способа ссылки на tools.jar достаточно переносимым образом, чтобы он хорошо работает в различных средах IDE и maven cmd, на рабочих станциях разработчиков и на наших серверах сборки (хотя все серверы - это просто различные варианты windows + oracle jdk). – bacar

+0

. Итак, вы согласитесь и подтвердите свой ответ, пожалуйста, если это кажется адекватным? Или вы все еще хотите знать? – kriegaex

+0

У меня нет принципиального возражения против маршрута отражения кстати. Я предпочитаю свой статический путь, но все же стоит взять на себя другое в качестве ответа - разные ситуации требуют разных решений. – bacar

0

Я нашел следующие работы (испытанные на 1.8.4), хотя он опирается на недокументированные функции aspectjweaver, поэтому не могут работать в разных версиях.

public static boolean isAspectJAgentLoaded() { 
    try { 
     org.aspectj.weaver.loadtime.Agent.getInstrumentation(); 
     return true; 
    } catch (UnsupportedOperationException e) { 
     return false; 
    } 
} 

Пояснение: когда AspectJ загружается в качестве агента, то org.aspectj.weaver.loadtime.Agent.premain(...) статический метод вызывается JVM. У этого есть побочный эффект, который мы можем проверить. Вызов getInstrumentation либо выбрасывает UnsupportedOperationException (если он не был инициализирован как агент) или успешно возвращается, если он был.

+0

Я не думаю, что это особенно практичный подход, потому что, если ткацкий агент не загружен, вероятно, * aspectjweaver.jar * не будет на пути к классу и ваш код не будет работать, но выдает исключение: «Исключение в потоке» main "java.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent'. Я бы предпочел использовать 'Class.forName (..)', как я сделал в своем ответе, а затем (только если успешно) называть 'getInstrumentation()' через отражение. См. Обновление моего ответа. – kriegaex

+0

Простое решение: поместите его в путь класса. Это (часто несущественная) стоимость этой проверки. Ошибка в случае, если она не на CP, прозрачна и легко фиксируется. Ваше предложение будет относиться к опечаткам (или изменениям в разных версиях) в квалифицированном классе или имени метода как «агент не загружен». Моя неудача быстро, что я предпочитаю.Во-вторых, мне непонятно, доступна ли jar, загруженная '-javaagent' для загрузчика классов по умолчанию, - вы протестировали свое предложение? (Я думаю, что все ставки отключены для обоих решений, если у вас есть пользовательские ClassLoaders) – bacar

+0

Посмотрите мое *** обновленное *** решение и, если хотите, вы имеете несколько предложений 'catch' для нескольких типов ошибок. Я думаю, что нехорошо позволить всему приложению выйти с необработанной ошибкой в ​​утилите, даже если эта ошибка возникает в том случае, когда вы хотите обрабатывать изящно. И если вы помещаете ткача в путь класса, это не означает, что LTW активен, потому что он все еще не загружается в качестве агента. Чтобы указать его дважды в командной строке, он интуитивно понятен. Мое решение превосходит, ИМХО. – kriegaex