Java注解初识

含义:可以理解为标签,用以提示和赋予类或属性信息

一、基础

1. 元注解

注解的注解,表明注解的信息

  • @Target:规定注解可以用在哪里
    • 取值:ElementType
      • TYPE:类和接口
      • FIELD:字段、枚举
      • METHOD
      • PARAMETER
      • CONSTRUCTOR:构造
      • LOCAL_VARIBLE:局部变量
      • ANNOTATION_TYPE:注解
      • PACKAGE:包
  • @Retention:规定注解可以存在于哪里
    • 取值:RetentionPolicy
      • SOURCE:源代码
      • CLASS:源代码、编译后的字节文件
      • RUNTIME:源代码中、 编译以后的字节码文件中、 运行时内存中, 程序可以通过反射获取该注解
  • Document:说明该注解将被包含在javadoc中
  • Inherited:说明子类可以继承父类中的该注解

2.预置注解

  • Deprecated:标识过时
  • SuppressWarnings:忽略警告

二、使用

1.通过反射获取注解信息

  • 对于属性字段注解
1
2
3
4
5
6
7
8
9
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{

private String name;
private String value;
}
// field也是通过反射获取的
MyAnnotation ma = field.getAnnotation(MyAnnotation.class);
  • Spring自定义接口参数校验注解 参考

示例:控制层接口方法参数校验

场景,提供的外部接口需校验传递参数的非空性

  1. 自定义注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /**
    * @author
    * @date 2021/7/20
    * @time 14:54
    * @description 非空注解
    */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyNotNull {

    /**
    * 默认不为空
    * @return
    */
    boolean empty() default false;
    }
  1. 控制层切面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    /**
    * @author
    * @date 2021/7/20
    * @time 15:12
    * @description 自定义控制层切面
    */
    @Component
    @Aspect
    public class MyControllerAspect {

    /**
    * 切线
    */
    private final String executeExpr = "execution(* com.mango.xx.web..*Controller.*(..))";


    /**
    * 环绕通知(增强处理)
    * @param proceedingJoinPoint 切点
    * @return
    * @throws IllegalAccessException
    */
    @Around(executeExpr)
    public Object processLog(ProceedingJoinPoint proceedingJoinPoint) throws IllegalAccessException {
    // 方法
    // Method method = ((MethodSignature)proceedingJoinPoint.getSignature()).getMethod();
    // Class rc = method.getReturnType();
    // 参数
    Object[] args = proceedingJoinPoint.getArgs();
    // 参数校验
    for (Object arg : args) {
    // 参数校验
    String msg = processArg(arg);
    if(!StringUtils.isEmpty(msg)){
    ResultMessage resultMessage = new ResultMessage();
    resultMessage.setSuccess(false);
    resultMessage.setCode(-1);
    resultMessage.setMsg(new StringBuilder(msg));
    return resultMessage;
    }

    }
    // 方法名称
    // String methodName = method.getName();

    Object res = null;
    try {
    // 继续执行方法
    res = proceedingJoinPoint.proceed(args);
    } catch (Throwable throwable) {
    throwable.printStackTrace();
    }

    return res;

    }

    /**
    * 解析注解
    * @param arg 参数
    * @return 提示信息;有值则校验不通过
    */
    private String processArg(Object arg) throws IllegalAccessException {
    Field[] fields = arg.getClass().getDeclaredFields();
    StringBuilder msg = new StringBuilder();
    for (Field field : fields) {
    if(field.isAnnotationPresent(MyNotNull.class)){
    field.setAccessible(true);
    MyNotNull annotation = field.getAnnotation(MyNotNull.class);
    boolean empty = annotation.empty();
    Object value = field.get(arg);
    Class fieldType = field.getType();
    if(fieldType == String.class){
    if(!empty){
    if(StringUtils.isEmpty(value)){
    msg.append(field.getName() + " 不能为空");
    msg.append(";");
    }
    }
    }
    }
    }
    return msg.toString();
    }
    }
  1. 使用注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 控制层方法
    @PostMapping(value = "/loadLove")
    public Result loadLove(@RequestBody heartVO){

    // ...
    return xx.loadLove(heartVO);
    }

    // 请求参数实体
    public class heartVO {

    @MyNotNull
    private String truth;

    @MyNotNull
    private String heart;

    // ...
    }

三、前置知识-AOP

1、基础

1.含义:Aspect Oriented Programming编程范式,程序设计思想

2.目的:把通用逻辑从业务逻辑分离出来

3.常用术语

  • Join point:拦截点,如某个业务方法
  • Pointcut:Joinpoint的表达式,表示拦截哪些方法;一个P对应多个J
  • Advice:要切入的逻辑,增强处理
    • BeforeAdvice:在方法前切入
    • AfterAdvice:在方法后切入
    • AfterReturningAdvice:在方法返回后切入,抛出异常则不会切入
    • AfterThrowingAdvice:在方法抛出异常时插入
    • AroundAdvice:在方法执行前后切入,可以中断或忽略原有流程的执行
  • Target Object:目标对象,被一个或多个切面通知的对象
  • Weaving:织入,将切面应用到目标对象的过程

4.切面代码织入时机

  • 编译期
  • 类加载期
  • 运行期

5.实现类别

  • 静态AOP实现:AOP框架再编译阶段对程序进行修改,生成静态的AOP代理类。以AspectJ为代表
  • 动态AOP实现:AOP框架在运行阶段动态生成AOP代理(实现对目标类的增强)。以Spring AOP为代表:jdk动态代理(实现接口)、cglib(继承)

6.实现内容

  • 定义普通业务组件
  • 定义切入点,一个切入点可以横切多个业务组件
  • 定义增强处理,增强处理就是在AOP框架为普通业务组织织入的处理动作

参考:https://www.jianshu.com/p/9aed3fb454df

2、Spring AOP

Spring中的AOP代理和其依赖关系由Spring的IOC容器负责生成、管理

1.定义切入点和增强处理的方式

  • 基于注解的“零配置”方式:使用@Aspect、@Pointcut等注解
  • 基于XML配置文件:Spring配置文件

2.注解方式

  • @Aspect – 作用是把当前类标识为一个切面供容器读取
  • @Pointcut – (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达
  • @Before – 标识一个前置增强方法,相当于BeforeAdvice的功能
  • @AfterReturning – 后置增强,相当于AfterReturningAdvice,方法退出时执行
  • @AfterThrowing – 异常抛出增强,相当于ThrowsAdvice
  • @After – final增强,不管是抛出异常或者正常退出都会执行
  • @Around – 环绕增强,相当于MethodInterceptor
------ 本文结束感谢您的阅读 ------

本文标题:Java注解初识

文章作者:MangoCheng

发布时间:2021年12月11日 - 19:51:40

最后更新:2021年12月11日 - 19:51:40

原始链接:http://mangocheng.com/posts/7039576b.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。