#java #aop #aspectj
#java #aop #aspectj
Вопрос:
Я пытаюсь определить аспект для внедрения регистратора.
Я хочу создать что-то вроде:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public aspect LogInjector {
private pointcut executionJoinPoints(): !within(LogInjector) amp;amp; execution (* *.*(..));
before(): executionJoinPoints(){
// Get class name of the executed code
clazz = ...
final Logger logger = LogManager.getLogger(clazz);
// Get method name of the executed code
method = ...
// Get params name, type and values triplet or values at least if the previous is not possible, of the executed code
params = ...
// Get call stack of the executed code
stack = ...
logger.trace("{}.{}({}) - {}", clazz.name(), method.name(), params, stack);
}
after(): executionJoinPoints(){
// Get class name of the executed code
clazz = ...
final Logger logger = LogManager.getLogger(clazz);
// Get method name of the executed code
method = ...
// Get return value or exception of the executed code
result = ...
logger.trace("{}.{} = {}", clazz.name(), method.name(), result);
}
}
Для этого я хочу получить метаданные / контекстные данные выполнения:
- исключения
- возвращаемые значения
Как можно получить эти метаданные / контекстные данные?
Комментарии:
1. Итак, вы задаете 6 разных вопросов (количество маркированных пунктов), ожидая, что кто-то сделает всю работу за вас. Я понимаю. Могу я спросить, читали ли вы какую-либо документацию, пробовали ли какие-либо методы, предлагаемые через автозаполнение в вашей точке соединения или аналогичные? Кроме того, известно ли вам о том, что такой универсальный аспект значительно замедлит работу вашего приложения, нацеливаясь на выполнение всех методов и извлекая всю возможную подробную информацию повсюду? Вы думали об отступах, чтобы отображать иерархии вызовов вместо создания трассировок стека для каждого вызываемого метода?
2. Для вызова подойдет отступ стека. С этим я могу справиться. С тех пор, как я задал вопрос, я разобрался со многими элементами, кроме как регистрировать возвращаемые значения и исключения. Кроме того, как мне ускорить аспект, не замедляя работу моего приложения? По сути, я хочу отслеживать через приложение протоколирование вызовов функций, возвращаемых значений и исключений.
Ответ №1:
Чтобы сохранить эффективность вашего аспекта, я рекомендую следующее:
- Ограничьте свой pointcut целевыми пакетами и классами, которые вы действительно хотите отлаживать. Не регистрируйте / не отслеживайте весь мир. Вы также можете использовать абстрактный базовый аспект с абстрактным точечным разрезом и расширить аспект до конкретного подаспекта с конкретным точечным разрезом. Последнее может быть предоставлено даже через конфигурацию XML, если вы используете переплетение времени загрузки.
- Используйте
around()
совет вместоbefore()
/after()
pair . Затем вам нужно только один раз вычислить некоторые из зарегистрированных значений и использовать их как до, так и после исходного вызова метода, выполняемого с помощьюproceed()
. - Просто регистрируйте
thisJoinPoint
вместо того, чтобы собирать вместе биты, содержащиеся в нем по умолчанию. Это уже даст вам тип точки соединения, сигнатуру метода, включая типы параметров и возвращаемое значение. - Не регистрируйте имена параметров, информация не добавляет реальной ценности. Кроме того, имена параметров подлежат рефакторингу и присутствуют только в том случае, если ваш код скомпилирован с отладочной информацией. Сохраняйте простоту и регистрируйте только значения параметров.
- В
around()
упомянутом выше совете вы можете заключитьproceed()
вызов вtry-catch-finally
и удобно обрабатывать и регистрировать любые исключения и трассировки стека и / или переносить проверенные исключения в AspectJSoftException
или простойRuntimeException
и повторно выбрасывать их. Все, что применимо к вашей ситуации. - Результаты вызова метода — это просто результаты
proceed()
, которые вы также должны вернуть изaround()
совета. Вы также можете вернуть что-то другое вместо этого (но оно должно иметь правильный возвращаемый тип) или полностью пропуститьproceed()
, если по какой-либо причине вы хотите пропустить выполнение целевого метода.
Все, что я только что сказал, написано в руководстве AspectJ или в любом другом руководстве AspectJ. Возможно, вы захотите прочитать некоторые из них в следующий раз, прежде чем задавать общий вопрос, подобный этому.
Комментарии:
1. Есть ли способ избежать
proceed()
иtry-catch
, но добиться того же.try-catch
вам нужно перестроить, чтобы это привело к измененной трассировке стека. Такжеproceed()
делает больше, чем просто захват возвращаемого значения с минимальными накладными расходами.2. Почему вас беспокоит преждевременная оптимизация, если по замыслу вы создаете медленный аспект, используемый только для отладки в любом случае? Никто в здравом уме не будет всегда регистрировать каждый вызов метода в производственной среде. Почему должны
proceed()
быть накладные расходы? Он просто вызывает целевой метод, который в любом случае необходимо выполнить. Вместо этого вы могли бы использоватьafter returning
after throwing
советы и, но тогда вам придется вычислять вещи для регистрации несколько раз. Для ваших целей иaround()
советов это просто самая эффективная вещь. Если вы думаете, что знаете лучше, будьте моим гостем и продолжайте.