Jersey 2.42中如何在自定义注解注入参数中获取方法注解?
解决Jersey参数注入时获取方法级注解的问题
问题原因
在参数注入阶段,ResourceInfo尚未被Jersey初始化并绑定到当前请求上下文,因此直接注入ResourceInfo会返回null。此时需要通过**参数注入解析器(ParamInjectionResolver)**来获取方法注解,因为解析器在处理参数注入时可以直接访问到参数所属的方法元数据。
解决方案一:通过动态绑定RequestScoped注解实例(推荐)
这种方式遵循HK2依赖注入规范,安全且无线程安全问题。
1. 修改参数注入解析器
让MyInjectedParamInjectResolver继承ParamInjectionResolver,在解析参数时获取方法上的MyAnnotation,并将其动态绑定到当前请求的作用域中:
public class MyInjectedParamInjectResolver extends ParamInjectionResolver<MyInjectedParam> { public MyInjectedParamInjectResolver() { super(MyInjectedParam.class); } @Override public Object resolve(Injectee injectee, ServiceHandle<?> root) { // 获取参数所属的资源方法 Method targetMethod = (Method) injectee.getParent(); MyAnnotation methodAnnotation = targetMethod.getAnnotation(MyAnnotation.class); // 将注解实例绑定到RequestScope,供Factory注入使用 ServiceLocator locator = root.getServiceLocator(); DynamicConfigurationService configService = locator.getService(DynamicConfigurationService.class); DynamicConfiguration dynamicConfig = configService.createDynamicConfiguration(); if (methodAnnotation != null) { dynamicConfig.bind( BuilderHelper.link(methodAnnotation) .to(MyAnnotation.class) .in(RequestScoped.class) .build() ); } else { // 处理方法无注解的情况,绑定null或默认值 dynamicConfig.bind( BuilderHelper.link(null) .to(MyAnnotation.class) .in(RequestScoped.class) .build() ); } dynamicConfig.commit(); // 调用父类逻辑完成参数注入 return super.resolve(injectee, root); } }
2. 修改Factory类
直接注入MyAnnotation,无需依赖ResourceInfo:
public class MyInjectedParamFactory implements Factory<MyType> { @Inject private MyAnnotation myAnnotation; @Override public MyType provide() { // 根据注解值创建MyType实例 String annotationValue = myAnnotation != null ? myAnnotation.value() : "defaultValue"; return new MyType(annotationValue); } @Override public void dispose(MyType instance) { // 按需清理资源 } }
3. 保持Feature配置不变
原有的MyInjectedParamFeature绑定逻辑无需修改,确保MyInjectedParamInjectResolver被注册为单例即可。
解决方案二:使用ThreadLocal传递注解信息
如果不想使用动态绑定,可以用ThreadLocal临时存储注解信息,但需注意异步请求场景下的线程安全问题,且要确保及时清理ThreadLocal:
1. 修改Factory类
添加ThreadLocal存储注解,并提供设置/清理方法:
public class MyInjectedParamFactory implements Factory<MyType> { private static final ThreadLocal<MyAnnotation> ANNOTATION_HOLDER = new ThreadLocal<>(); public static void setCurrentAnnotation(MyAnnotation annotation) { ANNOTATION_HOLDER.set(annotation); } public static void clearCurrentAnnotation() { ANNOTATION_HOLDER.remove(); } @Override public MyType provide() { MyAnnotation annotation = ANNOTATION_HOLDER.get(); String value = annotation != null ? annotation.value() : "default"; return new MyType(value); } @Override public void dispose(MyType instance) { // 请求结束后清理ThreadLocal clearCurrentAnnotation(); } }
2. 修改参数注入解析器
在解析参数时设置ThreadLocal的值:
public class MyInjectedParamInjectResolver extends ParamInjectionResolver<MyInjectedParam> { public MyInjectedParamInjectResolver() { super(MyInjectedParam.class); } @Override public Object resolve(Injectee injectee, ServiceHandle<?> root) { Method targetMethod = (Method) injectee.getParent(); MyAnnotation annotation = targetMethod.getAnnotation(MyAnnotation.class); MyInjectedParamFactory.setCurrentAnnotation(annotation); try { return super.resolve(injectee, root); } finally { // 可选:提前清理,避免线程复用导致的问题 // MyInjectedParamFactory.clearCurrentAnnotation(); } } }
关键说明
- 两种方案的核心都是在参数注入解析阶段获取方法注解,因为此时可以直接访问参数所属的方法元数据,而
ResourceInfo要到请求处理的后续阶段才会被初始化。 - 推荐使用第一种动态绑定方案,它完全依赖Jersey的请求作用域管理,无需手动处理线程安全问题。
内容的提问来源于stack exchange,提问作者David Sykes
相关产品推荐
相关产品推荐

