自定义注解+AOP

     在我们日常编程过程中,会用到许多注解,比如@Component、@Bean等注解,这些注解有什么好处呢?最明显的便是简洁代码,省略很多不必要的代码,同时注解也可以实现多样化。一般自定义注解步骤主要是,定义注解类-->注解类使用-->解析注解,在运行时或编译期发现标记进行特殊处理。这样对于整个项目或者多个项目中可以使用自定义注解标记,完成自己需要的特定操作,避免了每个使用处都有大篇幅的解析代码。本文主要讲解自定义注解结合AOP的应用,其中可以利用AOP编程识别注解标记进行处理。

   1.定义注解类  

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

    /**
     * 当前时间
     * @return
     */
    long time();

    /**
     * 日志内容
     * @return
     */
    String info() default "";

    /**
     * 日志类型
     * @return
     */
    LogType logtype() default LogType.INFO;

}

其中LogType枚举类:

public enum LogType {

    ERROR,

    INFO,

    DEBUG
}

自定义注解也需要元注解进行标记,元注解可以理解为接口或者抽象类,完成顶层基本功能。常见元注解主要有以下几类

1.@Target

    @Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的。它使用一个枚举类型定义如下:

public enum ElementType {
    /**类,接口(包括注解类型)或枚举的声明*/
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /**属性的声明*/
    /** Field declaration (includes enum constants) */
    FIELD,

    /**方法的声明*/
    /** Method declaration */
    METHOD,

    /**方法形式参数声明*/
    /** Formal parameter declaration */
    PARAMETER,

    /**构造参数的声明*/
    /** Constructor declaration */
    CONSTRUCTOR,

     /**局部变量的声明*/
    /** Local variable declaration */
    LOCAL_VARIABLE,

    /**注解类型声明*/
    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /**包声明*/
    /** Package declaration */
    PACKAGE,

    /**类型参数声明*/
    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     *类型的使用
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

2.@Retention

@Retention注解,主要表示在什么时期被识别,即其生命周期,常见生命周期如下枚举类:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

 目前比较常用的是RUNTIME,运行时识别,通过反射原理进行解析实现特定操作。

3.@Documented:是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中,标记则是,反之亦然。

4.@Inherited

@Inherited注解,是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解。@Inherited注解只对那些@Target被定义为ElementType.TYPE的自定义注解起作用。

 

 

2.注解使用

@RestController
public class TestController{
    @RequestMapping("/test")
    @LogInfo(time =0,info = "请求测试",logtype = LogType.ERROR)
    public void testLimit(){
        System.out.println("测试注解功能");
    }



}

3.解析注解

   对于识别到注解之后进行特定处理,实现多样化操作。

  

@Component
@Aspect
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(LogAspect.class);


    @Pointcut("@annotation(com.carson.cachedemo.annotation.LogInfo)")
    public void pointcut(){

    }



    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

        String url = request.getRequestURI();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method signatureMethod = signature.getMethod();
        LogInfo logInfo = signatureMethod.getDeclaredAnnotation(LogInfo.class);
        Date time = new Date(System.currentTimeMillis());
        LogType type = logInfo.logtype();
        switch (type){
            case INFO:
                logger.info("用户请求url={},time={},value={}",url,time,logInfo.info());
                break;
            case DEBUG:
                logger.debug("用户请求url={},time={},value={}",url,time,logInfo.info());
                break;
            case ERROR:
                logger.error("用户请求url={},time={},value={}",url,time,logInfo.info());
                break;
                default:
                    logger.info("用户请求url={},time={},value={}",url,time,logInfo.info());
                    break;




        }
    }
}

其中@Aspect注解表示引入AOP,@Compoment则是把这个类交给spring容器管理。

该类中引入了AOP(切面编程),需要引入以下依赖才会生效(缺一不可)

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

最后补齐springboot启动一个工程最基本的配置(这个就不细说了),然后调用接口,触发请求,得到如下结果:

上图说明注解生效。一个简单的注解例子,有助于帮助了解自定义注解的步骤。具体的需要举一反三,具体场景具体讨论。注解是为了简化冗余代码,也增加了灵活性。

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值