Фоновая проблема
Давным-давно, когда я был еще в Бронзе (и до сих пор в Бронзовом ранге), я пошел на собеседование, и интервьюер спросил меня, как получить класс и аннотации к методу.
В то время я тоже пользовался аннотациями, поэтому отвечал ровно, используяisAnnotationPresentОпределить, добавляется ли аннотация,getAnnotationПолучите объект аннотации, затем получите значение в аннотации.
Грубый код такой:
Class<?> clz = bean.getClass();
Method[] methods = clz.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Encrypt.class)) {
String uri = method.getAnnotation(Encrypt.class).value();
}
}
Когда я был самоуспокоен, интервьюер снова погнался за победой, поэтому при чтении аннотации есть ли какая-либо ситуация, из-за которой то, как вы только что сказали, не сможет успешно судить и читать?
Я смущен этим, есть ли еще ситуация, когда я не могу это прочитать? Раньше с таким не сталкивался, поэтому ответил интервьюеру однозначно, не читать невозможно, интервьюер улыбался......
В моих криптографических рамках обезьян-API-шифрования (Github.com/yinji huan / нет ...), Шифрование и дешифрование поддерживают идентификацию функциональной аннотации, фактически, читая заметки, преобразуйте операцию uri. Описанное выше начало используется для аннотаций операций чтения, когда мы программируем контроллер, который врезается в АОП, заметки не читаются, и сегодня мы делимся этой проблемой.
Обычно наш классcom.cxytiandi.eureka_client.controller.ArticleControllerВ этой форме, если используется АОП, он станетcom.cxytiandi.eureka_client.controller.ArticleController?EnhancerBySpringCGLIB?3323dd1eВот и все.
Решение первое
Полученный в данном случае Метод также является проксируемым, поэтому аннотации к Методу нельзя получить естественным путем.Теперь, когда причина известна, самое простое и быстрое решение — перехватить избыточный контент, а затем получить новый, не проксируемый , Объект класса, через этот объект класса, чтобы получить метод, чтобы вы могли получить аннотации к методу.
Class<?> clz = bean.getClass();
String fullName = clz.getName();
if (fullName.contains("EnhancerBySpringCGLIB") || fullName.contains("?")) {
fullName = fullName.substring(0, fullName.indexOf("?"));
try {
clz = Class.forName(fullName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
Method[] methods = clz.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Encrypt.class)) {
String uri = method.getAnnotation(Encrypt.class).value();
}
}
Решение 2
Хотя проблема решена, она по-прежнему кажется недостаточно элегантной, есть ли лучший способ? Мы можем использовать AnnotationUtils, предоставленные в Spring, для чтения аннотаций.
Encrypt encrypt = AnnotationUtils.findAnnotation(method, Encrypt.class);
if (encrypt != null) {
String uri = encrypt.value();
}
Что такое принцип annotationUtils.FindanNotation()? Почему он может получить аннотацию по методу post-proxy?
Если вы хотите узнать принцип, вы можете посмотреть только на исходный код. Есть слишком много исходных кодов, поэтому я не буду публиковать их. Просто вставьте немного ключа.
Во-первых, нужно построить AnnotationCacheKey, полученный из локального кеша, если таковой имеется, прямой возврат, что означает, что чтение из кеша будет слишком долгим:
AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
A result = (A) findAnnotationCache.get(cacheKey);
Затем следует судить, будет ли метод мостичен, если нет, возвращайте напрямую, если это так, получите аннотацию мостального метода, если нет, получите его через интерфейс.
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);
if (result == null) {
result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());
}
Я не буду продолжать позже, самый важный код на самом деле это предложение:
clazz = clazz.getSuperclass();
Поскольку прокси-сервер CGLIB будет динамически генерировать подкласс для целевого класса, нам нужно получить самый примитивный класс и напрямую использовать getSuperclass. ...
Для его получения рекомендуется использовать AnnotationUtils.Он инкапсулирует много логики и рассматривает проблемы во многих сценариях.Не повторяйте колесо.