如何使用Java定制注释和Spring AOP设置属性值?
我想使用定制的Java注释在使用Spring AOP(和/或AspectJ)的私有类属性中插入值。快速示例:
MyAnnotation.java:
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface MyAnnotation {
}
MyController.java:
public class MyControllerImpl implements MyController {
...
@MyAnnotation
private String var1;
@Override
public String getVarExample() {
// imagine this is a REST API that gets called on @GET
// request and returns a string
System.out.println(this.var1); // <-- I'd like this to be "helloworld"
// this is just for illustration
// of course, I will want to do
// something more meaningful with
// the 'var1' variable
return "ok"; <- unimportant for this example
}
...
MyAspect.java:
@Aspect
@Component
public class MyAspect {
@Pointcut("@annotation(com.mypackage.annotation.MyAnnotation)")
public void fieldAnnotatedWithMyAnnotation() {
}
@Around("fieldAnnotatedWithMyAnnotation()")
public Object enrichVar1(ProceedingJoinPoint pjp) throws Throwable {
// problem #1 - the program never enters here
// problem #2 - I need to figure out how to set up the var1 here
// to "helloworld" , how?
return pjp.proceed();
}
...
}
我希望发生什么?
我将调用并进入getVarExample()
,在它返回后,我希望在控制台或日志中看到";HelloWorld";。我想以某种方式使用AOP将var1
设置为自定义值。将使用@MyAnnotation
注释的任何属性变量都将设置为";HelloWorld";。我希望上面的例子是清楚的。
我尝试了什么?
我确保包名称中没有拼写错误,还摆弄了不同的AOP建议注释,如@Around
和@Before
。我还尝试了MyAnnotation
中的不同目标,结果是ElementType.FIELD
应该是正确的。
您能帮助我使其正常工作吗?
我知道这是可以做到的,但在网上找不到任何可用的示例。同样,我希望看到两个答案:
1.如何让切入点在MyController入口触发?我想在MyAspect
类的enrichVar1(..)
方法内捕获断点。
2.如何修改MyAspect
类的enrichVar1(..)
方法中带注释的var1
值?
我不知道我做错了什么。任何帮助都将不胜感激。谢谢!
在我的项目中正确设置了AOP。我之所以知道这一点,是因为我已经将AOP用于不同的事情(例如日志记录)。
更新#1:
请注意,var1
私有变量没有getter或setter。该变量将仅在MyControllerImpl
中使用。为了更好地说明这一点,我更改了getVarExample
的返回值。
解决方案
如我在评论中所说:
切入点指示符
@annotation()
拦截带注释的方法,而不是带注释的字段。为此,本机AspectJ有get()
和set()
。也就是说,如果迁移到AspectJ,切入点也需要更改。但我同意,坚持使用Spring AOP并注释getter方法而不是字段在这里可能就足够了。
但是因为您坚持要保持控制器类不变,所以这里是本机AspectJ解决方案。请阅读Using AspectJ with Spring Applications一章,了解如何使用@EnableLoadTimeWeaving
和JVM参数-javaagent:/path/to/aspectjweaver.jar
进行配置。
为了证明该解决方案确实独立于Spring工作,我根本没有使用Spring类或注释,只使用了POJO和本机AspectJ。您只需在您的Spring应用程序中执行相同的操作。请注意,与Spring AOP方面相比,本机AspectJ方面不需要@Component
注释。
package de.scrum_master.app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface MyAnnotation {}
package de.scrum_master.app;
public interface MyController {
String getVarExample();
}
package de.scrum_master.app;
public class MyControllerImpl implements MyController {
@MyAnnotation
private String var1;
@Override
public String getVarExample() {
System.out.println(this.var1);
return "ok";
}
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
MyController myController = new MyControllerImpl();
myController.getVarExample();
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@Pointcut("get(@de.scrum_master.app.MyAnnotation * *)")
public void fieldAnnotatedWithMyAnnotation() {}
@Around("fieldAnnotatedWithMyAnnotation()")
public Object enrichVar1(ProceedingJoinPoint pjp) throws Throwable {
System.out.println(pjp);
return "helloworld";
}
}
运行Application
时,控制台日志为:
get(String de.scrum_master.app.MyControllerImpl.var1)
helloworld
AspectJ手册解释field get and set join point signatures和field patterns的语法。
注意:我认为您的用例可能是黑客设计,而不是有效的应用程序设计。您应该重构而不是侵入这样的应用程序。
相关文章