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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

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

常用方法汇总

在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的时候,自己都没有实际的应用过。

好了。玩的开心!

相关文章
|
3天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
2天前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理策略和垃圾回收机制。首先介绍了Java内存模型的基本概念,包括堆、栈以及方法区的划分和各自的功能。进一步详细阐述了垃圾回收的基本原理、常见算法(如标记-清除、复制、标记-整理等),以及如何通过JVM参数调优垃圾回收器的性能。此外,还讨论了Java 9引入的接口变化对垃圾回收的影响,以及如何通过Shenandoah等现代垃圾回收器提升应用性能。最后,提供了一些编写高效Java代码的实践建议,帮助开发者更好地理解和管理Java应用的内存使用。
|
3天前
|
Java 开发者
深入解析Java中的异常处理机制
本文将深入探讨Java中异常处理的核心概念和实际应用,包括异常的分类、捕获、处理以及最佳实践。我们将通过具体示例展示如何有效使用try-catch块、throws关键字和自定义异常类,以帮助读者更好地理解和应用Java异常处理机制。
10 1
|
18天前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
1月前
|
存储 NoSQL Redis
redis 6源码解析之 object
redis 6源码解析之 object
53 6
|
3天前
|
存储 缓存 Java
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
什么是线程池?从底层源码入手,深度解析线程池的工作原理
|
7天前
|
开发工具
Flutter-AnimatedWidget组件源码解析
Flutter-AnimatedWidget组件源码解析
|
25天前
|
测试技术 Python
python自动化测试中装饰器@ddt与@data源码深入解析
综上所述,使用 `@ddt`和 `@data`可以大大简化写作测试用例的过程,让我们能专注于测试逻辑的本身,而无需编写重复的测试方法。通过讲解了 `@ddt`和 `@data`源码的关键部分,我们可以更深入地理解其背后的工作原理。
22 1
|
1月前
|
开发者 Python
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
66 1
|
1月前
|
开发者 Python
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
120 1

热门文章

最新文章

推荐镜像

更多