SpringBoot自定义注解

Spring框架中注解非常多,开发中有时需要自定义注解,该怎么做呢?

学习Spring自带的注解

package org.springframework.stereotype;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    String value() default "";
}

这是@Controller的注解,这个注解里包含了4个其他的注解,我大致介绍一下(其实源码里面说的很清楚):
1.@Target 用来表示注解作用范围,超过这个作用范围,编译的时候就会报错。
java.lang.annotation.ElementType

Target通过ElementType来指定注解可使用范围的枚举集合,枚举集合如下

package java.lang.annotation;

/**
* A program element type.  The constants of this enumerated type
* provide a simple classification of the declared elements in a
* Java program.
*
* <p>These constants are used with the {@link Target} meta-annotation type
* to specify where it is legal to use an annotation type.
*
* @author  Joshua Bloch
* @since 1.5
*/
public enum ElementType {
   /** Class, interface (including annotation type), or enum declaration */
   TYPE,

   /** Field declaration (includes enum constants) */
   FIELD,

   /** Method declaration */
   METHOD,

   /** Parameter declaration */
   PARAMETER,

   /** Constructor declaration */
   CONSTRUCTOR,

   /** Local variable declaration */
   LOCAL_VARIABLE,

   /** Annotation type declaration */
   ANNOTATION_TYPE,

   /** Package declaration */
   PACKAGE
}

ElementType的用法

取值注解使用范围
TYPE可用于类或者接口上
FIELD可用于域上
METHOD可用于方法上
PARAMETER可用于参数上
CONSTRUCTOR可用于构造方法上
LOCAL_VARIABLE可用于局部变量上
ANNOTATION_TYPE可用于注解类型上(被interface修饰的类型)
PACKAGE用于记录java文件的package信息

2.@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
}

作用范围如下:

取值作用范围
SOURCE在源文件中有效(即源文件保留)
CLASS在class文件中有效(即class保留)
RUNTIMR在运行时有效(即运行时保留)

3.@Documented
定义注解会被javadoc或者其他类似工具文档化
4.@Component
Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

自定义注解

package springboot_demol1.springboot_demol1.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 
 * @date 2019/12/5 15:40
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyFirstAnnotation {
    String value() default "";

}

定义切面类

创建完自定义注解后,该如何让注解起作用呢。这里以打印控制台字符串为例,当用自定义注解来修饰方法时,我们期望在方法执行的前后输出字符串,那么我们必须采用AOP(面向切面编程)的思想,理所当然地,我们需要定义切面类:

package springboot_demol1.springboot_demol1.annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * @author 
 * @date 2019/12/5 15:43
 */
@Aspect
@Component
public class MyFirstAspect {
    @Before("@annotation(MyFirstAnnotation)")
    public void beforePointcut(JoinPoint joinPoint) {
        MethodSignature methodSignature =  (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        MyFirstAnnotation annotation = method.getAnnotation(MyFirstAnnotation.class);
        String value = annotation.value();
        System.out.println("准备"+value);
    }

    @After("@annotation(MyFirstAnnotation)")
    public void afterPointcut(JoinPoint joinPoint) {
        MethodSignature methodSignature =  (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        MyFirstAnnotation annotation = method.getAnnotation(MyFirstAnnotation.class);
        String value = annotation.value();
        System.out.println(value+"结束");
    }

}

使用自定义注解

    @MyFirstAnnotation("给老库打电话")   //自定义的注解
    @RequestMapping(value = "/say")
    public void sayHello() {
        System.out.println("聊天中");
    }

控制台输出

准备给老库打电话
聊天中
给老库打电话结束 

使用环绕增强通知(Around)

修改 MyFirstAspect.java 代码

package springboot_demol1.springboot_demol1.annotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;


/**
 * @author 
 * @date 2019/12/5 15:43
 */
@Aspect
@Component
public class MyFirstAspect {

    @Around("@annotation(MyFirstAnnotation)")
    public void beforePointcut(ProceedingJoinPoint point, MyFirstAnnotation MyFirstAnnotation) throws Throwable{
        System.out.println("ANNOTATION welcome");
        System.out.println("ANNOTATION 调用方法:"+ MyFirstAnnotation.value());
        System.out.println("ANNOTATION 调用类:" + point.getSignature().getDeclaringTypeName());
        System.out.println("ANNOTATION 调用类名" + point.getSignature().getDeclaringType().getSimpleName());
        point.proceed(); //调用目标方法
        System.out.println("ANNOTATION login success");
    }
}

控制台输出:

ANNOTATION welcome
ANNOTATION 调用方法:给老库打电话
ANNOTATION 调用类:springboot_demol1.springboot_demol1.controller.EmpController
ANNOTATION 调用类名EmpController
聊天中
ANNOTATION login success

本篇将不定时更新 Spring 相关知识,一起查漏补缺学个痛快!欢迎点赞留香丨留言鼓励丨指出不足!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值