自定义注解autofill(案例及代码解读):一个简单案例三分钟搞懂自定义注解的一个常用场景理解自定义注解的使用方法,采用自定义注解+AOP切面

1. OperationType.java

public enum OperationType {
    INSERT,
    UPDATE
}
  • 功能:这是一个枚举类,定义了两种操作类型:INSERT(插入)和 UPDATE(更新)。在后续代码中,用于指定在哪些操作下进行自动填充。

2. AutoFillAnnotation.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 定义注解的作用目标为字段
@Target(ElementType.FIELD)
// 定义注解的保留策略为运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    // 注解的属性,默认值为空字符串
    String value() default "";
    // 新增 operationType 属性,指定在哪些操作类型下进行自动填充
    OperationType[] operationType() default {OperationType.INSERT, OperationType.UPDATE};
}
  • @Target(ElementType.FIELD):表明 @AutoFill 注解只能应用于类的字段上。
  • @Retention(RetentionPolicy.RUNTIME):意味着该注解在运行时可通过反射机制获取,这样才能在程序运行过程中对其进行处理。
  • String value() default "";:定义了一个名为 value 的属性,默认值为空字符串。这个属性可用于指定字段自动填充的值。
  • OperationType[] operationType() default {OperationType.INSERT, OperationType.UPDATE};:定义了一个 OperationType 数组类型的属性 operationType,默认值包含 INSERT 和 UPDATE 两种操作类型。该属性用于指定在哪些操作类型下对标记的字段进行自动填充。

3. User.java

// 示例类,使用 @AutoFill 注解
class User {
    @AutoFill(value = "John Doe", operationType = {OperationType.INSERT, OperationType.UPDATE})
    private String name;
    @AutoFill(value = "123 Main St", operationType = {OperationType.INSERT})
    private String address;

    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }
}
  • 这是一个示例类,展示了如何使用 @AutoFill 注解。
  • name 字段被 @AutoFill 注解标记,指定了填充值为 "John Doe",并且在 INSERT 和 UPDATE 操作时都进行填充。
  • address 字段也被 @AutoFill 注解标记,填充值为 "123 Main St",但仅在 INSERT 操作时进行填充。

4. AutoFillAspect.java

 

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Aspect
@Component
public class AutoFillAspect {

    // 定义切入点,这里假设标记了 @AutoFillMethod 的方法需要进行切入
    @Pointcut("@annotation(com.example.demo.AutoFillMethod)")
    public void autoFillMethods() {}

    @Before("autoFillMethods() && args(operationType, obj)")
    public void beforeAutoFillMethods(JoinPoint joinPoint, OperationType operationType, Object obj) throws IllegalAccessException {
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(AutoFill.class)) {
                AutoFill autoFill = field.getAnnotation(AutoFill.class);
                for (OperationType op : autoFill.operationType()) {
                    if (op == operationType) {
                        field.setAccessible(true);
                        field.set(obj, autoFill.value());
                        break;
                    }
                }
            }
        }
    }
}
  • @Aspect 和 @Component@Aspect 注解表明这是一个切面类,@Component 注解将该类作为 Spring 组件进行管理。
  • @Pointcut("@annotation(com.example.demo.AutoFillMethod)"):定义了一个切入点,该切入点匹配所有标记了 @AutoFillMethod 注解的方法。
  • @Before("autoFillMethods() && args(operationType, obj)"):这是一个前置通知,在切入点方法执行之前执行。它要求切入点方法的参数必须包含 OperationType 类型的 operationType 和一个对象 obj
  • 方法体
    • 获取对象的类信息和所有声明的字段。
    • 遍历所有字段,检查是否标记了 @AutoFill 注解。
    • 如果标记了 @AutoFill 注解,则获取注解的 operationType 属性,并检查当前操作类型是否匹配。
    • 如果匹配,则将注解的 value 属性值赋给该字段。

5. AutoFillMethod.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFillMethod {
}
  • 这是一个自定义注解,用于标记哪些方法需要被 AOP 切面切入。@Target(ElementType.METHOD) 表示该注解只能应用于方法上,@Retention(RetentionPolicy.RUNTIME) 表示在运行时可通过反射获取该注解。

6. UserService.java

import org.springframework.stereotype.Service;

@Service
public class UserService {

    @AutoFillMethod
    public void saveUser(OperationType operationType, User user) {
        System.out.println("Saving user: " + user.getName() + ", " + user.getAddress());
    }
}
  • @Service 注解将该类作为 Spring 服务组件进行管理。
  • saveUser 方法被 @AutoFillMethod 注解标记,因此在调用该方法时,AutoFillAspect 类中的前置通知会先执行,对 User 对象的相应字段进行自动填充。

7. MainApp.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MainApp implements CommandLineRunner {

    @Autowired
    private UserService userService;

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

    @Override
    public void run(String... args) throws Exception {
        User user = new User();
        OperationType operationType = OperationType.INSERT;
        userService.saveUser(operationType, user);
    }
}
  • @SpringBootApplication 是 Spring Boot 应用的核心注解,用于启用自动配置、组件扫描等功能。
  • 实现 CommandLineRunner 接口,重写 run 方法,在 Spring Boot 应用启动后执行该方法。
  • 在 run 方法中,创建一个 User 对象和一个 OperationType 对象,然后调用 UserService 的 saveUser 方法,触发 AOP 切面的前置通知,对 User 对象的字段进行自动填充。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值