Java自定义注解(详细版)

为什么要自定义注解

当然是为了装逼

为了能够在编写代码的时候,使得自己注入的代码更加直观,也显得耦合度更低。

正式步骤

先介绍通用的部分

第一步:声明自己要使用的注解

以此举例:

package com.pbinterface.demo;

import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    String value() default "111";
}

这里需要解释的有个部分:

  1. @Target注解:用于声明本注解是用于注解在什么地方上的,这里是用于注解在字段上面的;
  2. @Retention(RententionPolicy.RUNTIME) 这个注解则是用于注明本注解可以用反射获取;
  3. String value() 这一部分则是用于声明这个注解有什么属性,default用于声明默认值;

Target中可选的不仅有字段,还有方法、类、构造器等等,这里就不全部展开了。

然后就是特有的部分。

毕竟现在只是声明了有这么个注解,这个注解暂时还没有任何功能。

注解字段

依旧按照上述的例子,我们希望被这个注解注解的字段,自动注入我们预想的值,可以这么写:

@Component
public class AnnotationHandler implements BeanPostProcessor {

    // 使用反射获取字段并注入属性
    public Object postProcessAfterInitialization(Object bean, String BeanName){
        Class<?> clazz = bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if(field.isAnnotationPresent(MyAnnotation.class)){
                MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
                field.setAccessible(true);
                try {
                    field.set(bean, myAnnotation.value());
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return bean;
    }

}

这里声明了一个处理器,实现了BeanPostProcessor接口,使得这个类可以在Bean初始化的时候,进行属性注入。

注解方法

通过切面实现对于方法的注解。

//这是注解方法的注解样例
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
    String value() default "";
}

//这是实现功能的类
@Aspect
@Component
public class AnnotationHandler2 {
    @Pointcut("@annotation(com.pbinterface.demo.MyAnnotation2)")
    public void pointcut() {}

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        Object obj = joinPoint.getTarget();  // 获取到切点的实例,然后想干什么都可以了
    }
}

注解方法中参数

这个当然也可以使用切面的方式来达成,不过这里给出另一种方法。

// 这是被注解的类,需要注意的是,必须是Controller层的网络路径方法
@Controller
public class TestClass {
    @GetMapping("/test")
    public void run(@MyAnnotation3 String haha){
        System.out.println(haha);
    }
}

// 注解
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation3 {
    String value() default "AutoTest";
}

// 处理器,实现了这个接口
@Component
public class AnnotationHandler3 implements HandlerMethodArgumentResolver {

    // 判断参数是否符合条件
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(MyAnnotation3.class);
    }

    // 解析参数,返回值就是修改后的参数
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        return Objects.requireNonNull(parameter.getParameterAnnotation(MyAnnotation3.class)).value();
    }
}

// 配置类,若不配置,则不生效
@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final AnnotationHandler3 annotationHandler3;

    public WebConfig(AnnotationHandler3 annotationHandler3) {
        this.annotationHandler3 = annotationHandler3;
    }

    // 添加解析器
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(annotationHandler3);
    }

}

posted @ 2025-07-22 11:09  报废之人  阅读(439)  评论(0)    收藏  举报