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

使用注释和lombok对字段进行切入点

申屠锦
2023-03-14

简介:我正在使用Java与Spring boot 2.2.2和Lombok

我得到了这个示例类:

package com.example.demo.classz;


import com.example.demo.pack.MyAnnotation;
import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
public class FooClass {

    @NonNull
    @MyAnnotation
    private String str;

    private String uninterceptedString;

}

我想拦截所有用@MyAnnotation注释的“get”/“set”方法的调用。为了管理这个,我创建了这个界面:

package com.example.demo.pack;

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 com.example.demo.pack;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class AnnotatedFieldAspect {

    @Before("execution(* com.example.demo.classz.*.get*(..)) && @annotation(com.example.demo.pack.MyAnnotation)")
    public void interceptRead(JoinPoint thisJoinPoint) {
        log.info(thisJoinPoint.toString());
    }

    @Before("execution(* com.example.demo.classz.*.set*(..)) && @annotation(com.example.demo.pack.MyAnnotation) && args(newValue)")
    public void interceptWrite(JoinPoint thisJoinPoint, Object newValue) {
        log.info(thisJoinPoint + " -> " + newValue);
    }
}

最后为了测试所有,我做了一个简单的控制器

package com.example.demo;


import com.example.demo.classz.FooClass;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/")
    public String test() {
        FooClass fooClass = new FooClass("Foo");

        fooClass.setStr("Foo2");
        fooClass.getStr();

        return "Hi";
    }
}

我无法激活这些切入点,我不明白为什么。你能帮我吗?

我已经在StackOverflow上看到了一些类似的问题,比如:-带注释字段的Spring AOP切入点表达式-@AspectJ切入点,用于具有特定注释的类的所有方法

还有一些,但即使有他们的解决方案,我也没有成功。

一些配置的东西:

@EnableAspectJAutoProxy
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

和构建中的依赖项部分。格拉德尔:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.session:spring-session-core'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.2.2.RELEASE'
//  compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.5'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

谢谢

共有1个答案

魏凡
2023-03-14

正如kriegaex所提到的,FooClass不是由Spring容器管理的bean。你只能拦截一个春豆。

如果切入点表达式有效,则对代码更改的更改将使setter方法被拦截。

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

    @Data
    @RequiredArgsConstructor
    @Component
    @Scope(scopeName="prototype")
    public class FooClass {

        @NonNull
        @MyAnnotation
        private String str;

        private String uninterceptedString;

    }

并从应用程序上下文中获取FooClass bean。

FooClass fooClass = ctx.getBean(FooClass.class,"Foo");
fooClass.setStr("Foo2");
fooClass.getStr();

阅读有关@Component和@Scope的更多信息,以了解所做的更改。

@组件@范围

注意,Spring AOP只能拦截方法调用。在此处阅读文档

==SpringAOP能力和目标

Spring AOP目前仅支持方法执行连接点(建议在Spring bean上执行方法)。没有实现字段拦截,尽管可以在不破坏核心Spring AOP API的情况下添加对字段拦截的支持。如果您需要建议字段访问和更新连接点,请考虑使用一种语言,例如AeyJ。

出于同样的原因,以下Spring AOP PointCut表达式在您的情况下是有效的

@Before("execution(* com.example.demo.classz.*.get*(..))")
    public void interceptRead(JoinPoint thisJoinPoint) {
        log.info(thisJoinPoint.toString());
    }

    @Before("execution(* com.example.demo.classz.*.set*(..)) && args(newValue)")
    public void interceptWrite(JoinPoint thisJoinPoint, Object newValue) {
        log.info(thisJoinPoint + " -> " + newValue);
    }
 类似资料:
  • 我有一把刀: 问题是,当我试图使用DAO进行加载调用时,使用DynamoDBMapper以field d1作为哈希键来获取项目,它会抛出一个DynamoDBExc0019,说:为公共DAO. getField2()找到了空键,但实际上表的值对应于field d2。问题,这是因为Lombok注释而不是手动突变代码,还是一般来说我们一起使用Lombok和DynamoDBAnnotions?

  • 我有一个Java8/Maven/Spring Boot项目。我使用Javers来审核应用程序中的更改,然而,我创建了一个自定义注释,它放在类中的字段上方,如果更改,我希望对其进行审核。下面是一个示例类:

  • 我试图使用Hibernate的JPA注释实现以下关联: 或者,我需要基于主键进行带注释的关联。 如何实现这一点? 示例取自备用键上的Hibernate关联

  • 我试图在方法注释上创建一个Aeyj切入点,但我总是用不同的方法失败。我使用的是aspectj自动代理(我在Spring上下文中没有配置其他编织)。我的类如下所示: 所以我想知道为什么aspectj不会创建切入点。我设法使用执行(**(…)使其工作抛出一些exc)这对我来说很好,但我仍然想知道我做错了什么。 另外,由于是在接口中定义的,我指定了实现类的注释,有没有办法让它以这种方式工作?其他代理机制

  • 问题内容: 我正在运行Jersey REST服务。代表我的资源的POJO是带有JAXB(XML)注释的简单Java类(它们是从模式定义生成的-因此具有注释)。 我希望Jersey / Jackson忽略XML注释。我确实在我的web.xml这个配置(如提到这里): 我现在希望@XMLElement批注不再用于JSON字段命名策略。 但是看这个java领域(成员) 我仍然得到以下JSON表示形式: