Java自定义注解及使用场景

本文详细介绍了Java中的元注解、注解保留策略以及如何通过反射获取注解信息。此外,还展示了如何结合拦截器实现权限控制,以及使用AOP实现自定义注解的日志记录功能。通过实例代码演示了自定义注解在web层的拦截和AOP切面处理。
摘要由CSDN通过智能技术生成

参考博客

1.常用元注解

Target:注解修饰的对象范围

  • METHOD:用于描述方法
  • PACKAGE:用于描述
  • PARAMETER:用于描述方法变量
  • TYPE:用于描述类、接口或enum类型

Retention:注解保留时间长短

  • SOURCE:在源文件中有效,编译过程中会被忽略
  • CLASS:随源文件一起编译在class文件中,运行时忽略
  • RUNTIME:在运行时有效

2.利用反射获取注解信息

@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String desc();

    int length();
}
public class Test {

    @MyAnnotation(desc = "用户名",length = 10)
    String username;

    @MyAnnotation(desc = "hello方法",length = 100)
    public void hello(String msg){
        System.out.println("hello:"+msg);
    }

    @Override
    public String toString() {
        return "Test{" +
                "username='" + username + '\'' +
                '}';
    }

    public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Test test = new Test();
        Class<Test> clazz = Test.class;
        //获取属性上的注解
        Field field = clazz.getDeclaredField("username");
        MyAnnotation myAnnotation = field.getDeclaredAnnotation(MyAnnotation.class);
        System.out.println("myAnnotation.desc() = " + myAnnotation.desc());
        System.out.println("myAnnotation.length() = " + myAnnotation.length());
        //获取方法上的注解
        Method hello = clazz.getDeclaredMethod("hello", String.class);
        MyAnnotation myAnnotation1 = hello.getDeclaredAnnotation(MyAnnotation.class);
        System.out.println("myAnnotation1.desc() = " + myAnnotation1.desc());

    }
}

结果如下:

myAnnotation.desc() = 用户名
myAnnotation.length() = 10
myAnnotation1.desc() = hello方法

3.自定义注解+拦截器

拦截器:

public class SourceAccessInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法在业务处理器处理请求之前被调用");
        HandlerMethod method = (HandlerMethod) handler;
        LoginRequired loginRequired = method.getMethodAnnotation(LoginRequired.class);
        //方法上没有自定义注解
        if (loginRequired == null){
            return true;
        }
        //方法上有自定义注解
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write("你访问的资源需要先进行登录");
        response.flushBuffer();
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法在业务处理器处理请求执行完成后,生成视图之前执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion方法在DispatcherServlet完全处理完请求后被调用,可用于清理资源等");
    }
}

注册拦截器:

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SourceAccessInterceptor()).addPathPatterns("/**");
    }
}

web层:

@RestController
public class LoginController {

    @LoginRequired
    @GetMapping("/a")
    public String a(){
        System.out.println("你正在访问资源A---前");
        System.out.println("a");
        System.out.println("你正在访问资源A---后");
        return "你正在访问资源A";
    }
    @GetMapping("/b")
    public String b(){
        System.out.println("你正在访问资源b---前");
        System.out.println("b");
        System.out.println("你正在访问资源b---后");
        return "你正在访问资源b";
    }
}

访问b资源:
在这里插入图片描述
访问a资源:
在这里插入图片描述

自定义注解+AOP

添加AOP依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

自定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}

AOP配置类:

@Aspect
@Component
public class MyLogAspect {

    //@annotation表示这个切点在一个注解上,后面带上这个注解的全类名
    @Pointcut("@annotation(MyLog)")
    public void logPointCut(){

    }

    @Around("logPointCut()")
    public Object logAround(ProceedingJoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        System.out.println("joinPoint.getThis():" + joinPoint.getThis());
        System.out.println("joinPoint.getTarget():" + joinPoint.getTarget());

        //获取入参
        Object[] params = joinPoint.getArgs();
        StringBuilder sb = new StringBuilder();
        for (Object param : params) {
            sb.append(param).append("; ");
        }

        System.out.println("进入[" + methodName + "]方法,参数为:" + sb.toString());

        Object object = null;

        try {
            //接收方法的返回值
            object = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        System.out.println(methodName + "方法执行结束");
        return object;
    }
    
}

添加web层接口:

    @MyLog
    @GetMapping(value = "/c/{source_name}")
    public String sourceC(@PathVariable("source_name") String sourceName){
        System.out.println("你正在访问资源C,sourceName:"+sourceName);
        System.out.println("你正在访问资源C---前");
        System.out.println("你正在访问资源C---后");
        return "你正在访问资源C";
    }

打印信息如下:
在这里插入图片描述

preHandle方法在业务处理器处理请求之前被调用
joinPoint.getThis():com.fanle.LoginController@3827ed1d
joinPoint.getTarget():com.fanle.LoginController@3827ed1d
进入[sourceC]方法,参数为:helloworld; 
你正在访问资源C,sourceName:helloworld
你正在访问资源C---前
你正在访问资源C---后
sourceC方法执行结束
postHandle方法在业务处理器处理请求执行完成后,生成视图之前执行
afterCompletion方法在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
Java中的自定义注解是一种在代码中声明的特殊标记,用于在运行时对代码进行处理。通过定义注解,我们可以在代码中添加一些额外的元数据或标记信息,以实现对代码的自定义处理。使用自定义注解可以简化代码的编写和维护,提高代码的可读性和可维护性。 自定义注解使用场景有很多,以下是一些常见的使用场景: 1. 代码检查和规范:通过定义注解并在代码中添加注解,可以对代码进行静态检查,以确保代码符合规范和标准。例如,可以定义一个@NonNull注解用于标记不允许为null的参数或返回值,通过编译器插件或静态检查工具进行检查,从而避免了空指针异常。 2. 代码生成:通过定义注解和处理器,可以自动生成一些重复性的代码,提高开发效率。例如,可以定义一个@Entity注解用于标记实体类,通过注解处理器自动生成数据库表的建表语句或实体类的序列化/反序列化方法。 3. 运行时的动态处理:通过定义注解,并在运行时使用反射机制获取注解信息,可以实现一些动态处理的功能。例如,可以定义一个@Cacheable注解用于标记需要缓存的方法,然后使用反射在方法执行前判断是否有缓存数据,如果有则直接返回缓存结果,提高系统性能。 4. 测试框架:通过定义注解和处理器,可以实现自定义的测试框架。例如,可以定义一个@Test注解用于标记测试方法,然后使用注解处理器在测试运行时自动执行标记的测试方法。 总之,自定义注解Java语言中一种强大的元数据扩展机制,可以在代码中实现各种功能的自定义处理。通过合理设计和使用自定义注解,可以提高代码的可读性、可维护性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值