Интервьюер попросил меня использовать аннотации, чтобы не наступить на яму

Java

Фоновая проблема

Давным-давно, когда я был еще в Бронзе (и до сих пор в Бронзовом ранге), я пошел на собеседование, и интервьюер спросил меня, как получить класс и аннотации к методу.

В то время я тоже пользовался аннотациями, поэтому отвечал ровно, используя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.Он инкапсулирует много логики и рассматривает проблемы во многих сценариях.Не повторяйте колесо.

猿天地