• java自定义注解学习(三)_注解解析及应用


    上篇文章已经介绍了注解的基本构成信息。这篇文章,主要介绍注解的解析。毕竟你只声明了注解,是没有用的。需要进行解析。主要就是利用反射机制在运行时进行查看和利用这些信息

    常用方法汇总

    在Class、Field、Method、Constructor中都有如下方法:

    //获取所有的注解
    public Annotation[] getAnnotations()
    //获取所有本元素上直接声明的注解,忽略inherited来的
    public Annotation[] getDeclaredAnnotations()
    //获取指定类型的注解,没有返回null
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
    //判断是否有指定类型的注解
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
    

    Annotation 是一个借口,它表示注解,源码为:

    public interface Annotation {
        boolean equals(Object obj);
        int hashCode();
        String toString();
        //返回真正的注解类型
        Class<? extends Annotation> annotationType();
    }
    

    实际上,所有的注解类型、内部实现时,都是扩展的Annotation

    对于Method和Contructor,他们都有方法参数

    public Annotation[][] getParameterAnnotations()
    

    应用注解

    日常工作中,每个公司都会自定义注解进行记录日志的,我们就做一个简单的记录日志操作的注解,结合aop和springboot

    1.建立springboot项目

    这里不再赘述,主要需要引入aop

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

    2.定义自定义注解

    package com.kevin.anno.annotation;
    
    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 KevinLog {
        String value() default "";
    }
    
    

    3.定义aspect及解析注解

    package com.kevin.anno.aspect;
    
    import com.kevin.anno.annotation.KevinLog;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    
    @Aspect
    @Component
    public class LogAscpect {
    
        private final static Logger logger = LoggerFactory.getLogger(LogAscpect.class);
    
        @Pointcut("@annotation(com.kevin.anno.annotation.KevinLog)")
        public void log() {
        }
    
        @Around("log()")
        public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable {
            Object object = null;
            long start = System.currentTimeMillis();
    
            Method method = ((MethodSignature) MethodSignature.class.cast(point.getSignature())).getMethod();
            KevinLog kevinLog = method.getAnnotation(KevinLog.class);
    
            String operationName = kevinLog.value();
            object = point.proceed(point.getArgs());
            long end = System.currentTimeMillis();
            Long excuteTime = end - start;
    
            print(operationName, excuteTime, point);
            return object;
        }
    
        private void print(String operationName, Long excuteTime, ProceedingJoinPoint point) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            //operationName
            logger.info("operationName={}", operationName);
            //time
            logger.info("time={}", excuteTime);
            // url
            logger.info("url={}", request.getRequestURL());
            //method
            logger.info("method = {}", request.getMethod());
            //ip
            logger.info("ip = {}", request.getRemoteAddr());
            //类方法
            logger.info("class_method={}", point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName());
            //参数
            logger.info("args = {}", point.getArgs());
        }
    
    
    }
    
    

    4. 在请求方法上加上自定义注解

    package com.kevin.anno.controller;
    
    import com.kevin.anno.annotation.KevinLog;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @RequestMapping(value = "/hello")
        @KevinLog("kevin test !")
        public String hello() {
            return "hello kevin";
        }
    
    }
    
    

    5.启动测试

    访问:http://localhost:8080/hello

    页面出现:hello kevin

    控制台打印信息如下:

    2018-10-22 10:38:22.456  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno         : operationName=kevin test !
    2018-10-22 10:38:22.456  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno.aspect.LogAscpect         : time=7
    2018-10-22 10:38:22.456  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno.aspect.LogAscpect         : url=http://localhost:8080/hello
    2018-10-22 10:38:22.456  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno.aspect.LogAscpect         : method = GET
    2018-10-22 10:38:22.457  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno.aspect.LogAscpect         : ip = 0:0:0:0:0:0:0:1
    2018-10-22 10:38:22.457  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno.aspect.LogAscpect         : class_method=com.kevin.anno.controller.HelloController.hello
    2018-10-22 10:38:22.457  INFO 3916 --- [nio-8080-exec-2] com.kevin.anno.aspect.LogAscpect         : args = {}
    

    总结

    其实, 大家可以自己写这玩玩,比较这个demo还用到了aop,工作中很少接触到aop。以至于面试的时候,问你aop的时候,自己都没有实际的应用过。

    好了。玩的开心!

  • 相关阅读:
    RSAUtils非对称加密
    计算日期之间的时间差
    面向注解的切面实现
    多个切面执行同一个方法
    spring切面拦截实现
    三种实现日志过滤器的方式 (过滤器 (Filter)、拦截器(Interceptors)和切面(Aspect))
    redis实现 msetex和 getdel命令
    mvn修改版本号命令
    shell脚本实例-while实现批量创建用户
    shell脚本实例-for实现批量主机的探测
  • 原文地址:https://www.cnblogs.com/zhenghengbin/p/9828954.html
Copyright © 2020-2023  润新知