如何在无注解类访问权限时获取方法注解的值
问题
我正在编写一个Jar包解析插件,使用URLClassLoader通过反射访问Jar包中的类。已知目标注解的名称,能在字节码中找到对应类,但当前代码无法直接访问注解类本身,求解决办法。
大致实现逻辑如下:
Path pathToJar = Paths.get("/a/b/c/Application.jar"); List<Class<?>> allJarClasses = loadAllJarClasses(pathToJar); String annotationName = "MyAnnotation"; getValueFromAnnotationWithName(annotationName, allJarClasses); // --- public String getValueFromAnnotationWithName(String annotationName, List<Class<?>> classes) { classes.forEach(cl -> { Method[] methods = ...// 获取方法 for(Method m : methods) { Annotation[] annotations = ...// 从方法获取注解 for (Annotation a: annotations) { if (a.annotationType().getName().matches(".*" + annotationName)) { return getValueFromAnnotation("someValueName", a); // <- 此处需要帮助 } } } }); }
补充说明:
在IntelliJ IDEA调试时能看到注解的值,执行annotationMethod.toString()得到结果:
@ru.sparural.kafka.annotation.KafkaSparuralMapping(value="file/create")
解决方案
因为无法直接引入注解类,只能通过反射获取注解的属性值,以下是两种可行的实现方式:
方式一:直接反射调用注解的属性方法
注解本质是接口,每个属性都是接口的方法,可通过反射调用对应方法取值:
public String getValueFromAnnotation(String valueName, Annotation annotation) { try { // 获取注解中对应属性的方法 Method valueMethod = annotation.annotationType().getMethod(valueName); // 调用方法获取属性值 return (String) valueMethod.invoke(annotation); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); return null; } }
方式二:通过InvocationHandler获取注解的属性映射
注解实例是动态代理对象,可通过Proxy.getInvocationHandler()拿到它的属性存储容器直接取值:
public String getValueFromAnnotation(String valueName, Annotation annotation) { if (Proxy.isProxyClass(annotation.getClass())) { InvocationHandler handler = Proxy.getInvocationHandler(annotation); try { // 反射获取代理对象中存储注解属性的memberValues字段 Field memberValuesField = handler.getClass().getDeclaredField("memberValues"); memberValuesField.setAccessible(true); Map<String, Object> memberValues = (Map<String, Object>) memberValuesField.get(handler); return (String) memberValues.get(valueName); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); return null; } } return null; }
注意事项
- 确保
URLClassLoader已加载目标注解类:如果注解类在目标Jar中,加载Jar时需包含它;如果注解类在外部依赖中,要把依赖Jar加入URLClassLoader的路径,否则会抛出类找不到的异常。 - 方式二依赖JDK动态代理的内部实现(
memberValues字段),大部分JDK版本适用,但版本变更可能失效,优先推荐方式一。
内容的提问来源于stack exchange,提问作者SP QRT
相关产品推荐
相关产品推荐

