当前位置: 首页 > 知识库问答 >
问题:

如何使用Java自定义注释和Spring AOP设置属性值?

扈沛
2023-03-14

我想使用自定义Java注释,使用Spring AOP(和/或AspectJ)在私有类属性中插入一个值。快速示例:

我的注释。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
    }
    ...

我的方面。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建议注释,如前后的和前后的。我还在MyAnnotation中尝试了不同的目标,最终得到了ElementType。字段应正确。

我知道这是可以做到的,但在网上找不到任何有效的例子。我想再次看到两个答案:

1.如何在MyController入口触发切入点?我想在enrichVar1(..)中捕捉一个断点 MyAspect类的方法。

2.enrichVar1(..)中带注释的值如何修改 MyAspect类的方法?

我不知道我做错了什么。任何帮助都将不胜感激。非常感谢。

AOP在我的项目中设置正确。我知道这一点,因为我已经在为不同的事情使用AOP(例如日志记录)。

更新#1:

请注意,var1私有变量没有getter或setter。该变量将仅在MyControlllerImpl中使用。为了更好地说明这一点,我更改了getVarexample返回值。

共有2个答案

谢翰学
2023-03-14

从Spring文档来看,Spring AOP确实支持SpringBeans的方法执行连接点。为了使字段访问连接点工作,您需要使用AspectJ后端和AOP的加载时编织。

但是对于您的情况,不需要使用字段连接点,您可以将注释放在getter上,这应该有效。

郑俊彦
2023-03-14

正如我在评论中所说:

切入点指示器截取带注释的方法,而不是带注释的字段。为此,本机AspectJ有get()set()。一、 例如,如果迁移到AspectJ,切入点也需要更改。但我同意,在这里,坚持Spring AOP并注释getter方法而不是字段可能就足够了。

但是因为您坚持要保持控制器类不变,所以这里有一个原生的AeyJ解决方案。请阅读将AeyJ与Spring应用程序一起使用一章,了解如何使用@EnableLoadTime编织和JVM参数-javaagent:/path/to/aspectjweaver.jar配置它。

为了证明这个解决方案确实独立于Spring工作,我根本没有使用Spring类或注释,只有POJO和原生AspectJ。您可以在Spring应用程序中简单地执行相同的操作。请注意,与Spring AOP方面相比,本机AspectJ方面不需要组件注释。

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";
  }
}

运行应用程序时,控制台日志将为:

get(String de.scrum_master.app.MyControllerImpl.var1)
helloworld

AspectJ手册解释了字段获取和设置连接点签名和字段模式的语法。

注意:我认为您的用例可能是黑客攻击,而不是有效的应用程序设计。你应该重构而不是侵入这样的应用程序。

 类似资料:
  • 我想根据“配置文件”设置注释的值。 让我举个例子来解释; 在上面的例子中,我们可以看到活动的“配置文件”是PROD,但是假设我们想要使用DEV配置文件,我们将不得不注释来自PROD的@Table注释,并取消注释DEV@Table注释。 如果这只针对一个实体,那不会是一个问题,但我有很多实体都有这种情况,所以我不认为这是处理这种即兴“简介”的方式。 你知道有什么办法可以解决这种情况吗?

  • 例如,我有一个bean类 我想设置这个属性的值。 在Xml配置中,我可以 我如何实现同样的事情,即设置属性的值使用Java注释?现在我已经读到,我们可以使用@Value注释使用一些属性文件,但它不能不使用属性文件,做的方式,我通过xml文件?或者使用属性文件是必要的? 我可以通过包含

  • 问题是我写了简单的注释处理器,它根本不处理类型注释。simple annotations processor的源代码如下所示: 有什么想法如何使用或如何通过SimpleAnnotationsProcessor访问类型注释吗?使用可插入的注释处理API对我来说是不必要的,我认为它会比Java反射有更好的性能。无论如何,我也不知道如何通过Java反射访问类型注释。

  • 我发现了几个与此相关的(不是重复的)问题,但它们不能让我满意。 我无法理解在哪里以及为什么要使用? 我在一本书中读到了一个自定义注释的示例,但没有详细解释。 myMeth()内的输出与预期一致。 关于这个例子,我有几个问题。 1-如何在此程序中使用和?或

  • 我们结合使用JAX-WS和JAXB来接收和解析XML web服务调用。所有这些都是基于注释的,也就是说,我们在代码中从未掌握过JAXBContext。我需要在解组器上设置一个自定义ValidationEventHandler,这样,如果某个特定字段的日期格式不被接受,我们就可以捕获错误并在响应中报告一些好消息。我们在讨论的字段上有一个XMLJavaTypeAdapter,它进行解析并引发异常。我看