Java 如何在运行时更改方法注释值?

Java 如何在运行时更改方法注释值?,java,reflection,annotations,aop,Java,Reflection,Annotations,Aop,我有一个控制器 @MessageMapping("/room.register") @SendTo("#{sendTo}") public Message addUser(@Payload Message message, SimpMessageHeaderAccessor headerAccessor) { headerAccessor.getSessionAttributes().put("username", message.

我有一个控制器

@MessageMapping("/room.register")
@SendTo("#{sendTo}")
public Message addUser(@Payload Message message,
                       SimpMessageHeaderAccessor headerAccessor) {
    headerAccessor.getSessionAttributes().put("username", 
    message.getSender());
    return message;

}
我想在运行时更改SendTo注释的值

我试着这样做:

@Aspect
public class SendToAspect {
@Autowired
private WebSocketConfigurationProperties webSocketConfigurationProperties;


@Around("execution (public * *(..)) && @annotation(ann)")
public Object execute(final ProceedingJoinPoint point, final SendTo ann) 
throws Throwable {

    MethodSignature signature = (MethodSignature) point.getSignature();
    Method method = signature.getMethod();
    method.setAccessible(true);

    Annotation[] annotations = method.getDeclaredAnnotations();
    for (int i = 0; i < annotations.length; i++) {
        if (annotations[i].annotationType().equals(SendTo.class)) {
            annotations[i] = new SendTo() {

                @Override
                public Class<? extends Annotation> annotationType() {
                    return SendTo.class;
                }

                @Override
                public String[] value() {
                    return new String[] 
                            {webSocketConfigurationProperties.getTopic()};
                }
            };
        }
    }
    return point.proceed();
}

}
@方面
公共类SendToAspect{
@自动连线
私有WebSocketConfigurationProperties WebSocketConfigurationProperties;
@关于(“执行(公共**(..)&&&@注释(ann)”)
公共对象执行(最终过程连接点,最终发送到ann)
扔掉的{
MethodSignature=(MethodSignature)point.getSignature();
Method=signature.getMethod();
方法setAccessible(true);
Annotation[]annotations=method.getDeclaredAnnotations();
for(int i=0;i
你可能想调查一下

  • 对于
    @SendTo
    @SubscribeMapping
    以及
  • 我的答案是关于如何做
也许这两种方法中的一种对你来说是可行的

话虽如此,您也可以转向原力的黑暗面,真正尝试操纵注释值

示例驱动程序应用程序:

package de.scrum\u master.app;
导入org.springframework.messaging.handler.annotation.SendTo;
公共类应用程序{
@发送至(“原件”)
public void doSomething()抛出NoSuchMethodException、SecurityException{
SendTo SendTo=Application.class
.getDeclaredMethod(“doSomething”)
.getAnnotationsByType(SendTo.class)[0];
System.out.println(sendTo.value()[0]);
}
公共静态void main(字符串[]args)抛出NoSuchMethodException、SecurityException{
新应用程序().doSomething();
新应用程序().doSomething();
新应用程序().doSomething();
}
}
如果没有方面,这将打印:

原件
起初的
起初的
这里没有什么奇怪的。现在使用这个特性(在SpringAOP中,您还应该添加一个
@组件
注释):

package de.scrum\u master.aspect;
导入java.lang.annotation.annotation;
导入java.lang.reflect.Field;
导入java.lang.reflect.Proxy;
导入java.util.Map;
导入org.aspectj.lang.JoinPoint;
导入org.aspectj.lang.annotation.Aspect;
导入org.aspectj.lang.annotation.Before;
导入org.springframework.messaging.handler.annotation.SendTo;
@面貌
公共类SendToAspect{
@在(“执行(**(..)&&&&@注释(发送到)”之前
公共void changeAnnotation(JoinPoint thisJoinPoint,SendTo SendTo){
System.out.println(thisJoinPoint+“\n[之前]”+sendTo);
changeAnnotationValue(sendTo,“value”,新字符串[]{“changed”});
System.out.println(“[之后]”+sendTo);
}
@抑制警告(“未选中”)
公共静态对象changeAnnotationValue(注释注释、字符串键、对象newValue){
对象处理程序=Proxy.getInvocationHandler(注释);
字段f;
试一试{
f=handler.getClass().getDeclaredField(“memberValues”);
}catch(NoSuchFieldException | SecurityException e){
抛出新的非法状态异常(e);
}
f、 setAccessible(true);
映射成员值;
试一试{
memberValues=(Map)f.get(handler);
}捕获(IllegalArgumentException | IllegalAccessException e){
抛出新的非法状态异常(e);
}
对象oldValue=memberValues.get(键);
如果(oldValue==null | | oldValue.getClass()!=newValue.getClass()){
抛出新的IllegalArgumentException();
}
memberValues.put(key,newValue);
返回旧值;
}
}
现在控制台日志是:

执行(void de.scrum\u master.app.Application.doSomething())
[之前]@org.springframework.messaging.handler.annotation.SendTo(值=[原始])
[在]@org.springframework.messaging.handler.annotation.SendTo之后(值=[更改])
改变
执行(void de.scrum\u master.app.Application.doSomething())
[之前]@org.springframework.messaging.handler.annotation.SendTo(值=[更改])
[在]@org.springframework.messaging.handler.annotation.SendTo之后(值=[更改])
改变
执行(void de.scrum\u master.app.Application.doSomething())
[之前]@org.springframework.messaging.handler.annotation.SendTo(值=[更改])
[在]@org.springframework.messaging.handler.annotation.SendTo之后(值=[更改])
改变
正如您在上面的日志中所看到的,如果您只需要更改一次值,并且其值不是动态的,那么每次调用该方法时执行aspect通知是低效的。相反,您也可以从aspect之外的其他位置操纵注释,或者向aspect添加一个静态布尔成员,以便操纵anno只有一次:

static boolean done=false;
@在(“执行(**(..)&&&&@注释(发送到)”之前
公共void changeAnnotation(JoinPoint thisJoinPoint,SendTo SendTo){
如果(完成)
返回;
System.out.println(thisJoinPoint+“\n[之前]”+sendTo);
changeAnnotationValue(sendTo,“value”,新字符串[]{“changed”});
System.out.println(“[之后]”+sendTo);
完成=正确;
}
那么输出将是:

执行(void de.scrum\u master.app.Application.doSomething())
[之前]@org.springframework.messaging.handler.annotation.SendTo(值=[原始])
[在]@org.springframework.messaging.handler.annotation.SendTo之后(值=[更改])
改变
改变
改变
另见:

  • 上面我的方面中的项目、助手方法取自
  • 顺便说一句,JavaEx的灵感也来自于

注释是在编译时确定的,这就是为什么它们只能包含常量