AOP和Annotation

AspectJ
使用Spring Aop验证方法参数是否合法
框架开发之Java注解的妙用i

Spring AOP原理

1. Annotation Basics

注解的分类

  • 按照来源划分: JDK注解, 第三方注解, 自定义注解
  • 按照运行机制: RententionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME(运行时注解, 可以通过反射读取)
  • 使用目标(Target): ElementType(TYPE, FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE)
  • 注解的解析: 通过反射获取类、方法、成员变量上的RUNTIME注解信息, 从而实现动态控制程序运行逻辑.

2. 自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Documented/**标识这个注解会包含在生成javadoc中包含**/

@Inherited/**if the class declaration has no annotation for this type @MyAnnotation,then the class's superclass will automatically be queried for the annotation type.**/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

/**1. 成员变量以无参无异常的方式声明**/
/**2. 合法的成员变量只能是基本的数据类型, String, Class, Annotation,Enumeration等**/
/**3. 如果注解只有一个成员变量,只能声明为value**/
/**4. 注解可以没有成员, 没有成员变量的注解称为标识注解**/
String name(); //String
int id() default 0; //基本数据类型
AnotherAnnotation anno(); //注解
Class clazz(); //Class
Gender genderEnum(); //枚举
}

3. 使用Spring AOP实现注解参数校验

代码来源于使用Spring Aop验证方法参数是否合法, 做了简化和注释.

  • maven配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <dependencies>

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

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!--<version></version>-->
    </dependency>

    <!--Spring AOP-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    </dependencies>
  • ValidateField.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package com.jay;

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

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

    /**参数是方法的第几个参数: 需要根据这个index去joint.getArgs()数组中定位实际参数值**/
    int index() default -1;

    boolean notNull() default false;

    int maxLen() default -1;

    int minLen() default -1;

    int maxValue() default -1;

    int minValue() default -1;
    }
  • ValidateGroup.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.jay;

    import java.lang.annotation.*;

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ValidateGroup {

    ValidatedField[] fields();
    }
  • ValidationHandler.java

    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
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    package com.jay;

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;

    import java.lang.annotation.Annotation;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;


    @Component
    @Aspect
    public class ValidationHandler {

    @Around("@annotation(com.jay.ValidateGroup)")
    public Object validateAround(ProceedingJoinPoint joint) throws Throwable {
    boolean flag = false;

    System.out.println("***************************************************");

    try {
    /**获取被注解的方法名**/
    String methodName = joint.getSignature().getName();

    /**获取被注解的对象**/
    Object target = joint.getTarget();

    /**获取被注解的参数**/
    Object[] args = joint.getArgs();

    /**根据被注解的方法名和对象的Class获取被注解的方法**/
    Method method = getMethdByClassAndName(target.getClass(), methodName);

    /**获取注解**/
    ValidateGroup group = method.getAnnotation(ValidateGroup.class);

    /**根据注解(条件)和参数(实际值)进行参数校验**/
    flag = validateField(group.fields(), args);

    }catch (Exception e) {
    flag = false;
    }finally {
    if(flag){
    System.out.println("验证通过");
    return joint.proceed();
    }else{ //这里使用了Spring MVC ,所有返回值应该为Strng或ModelAndView ,如果是用Struts2,直接返回一个String的resutl就行了
    System.out.println("验证未通过");
    return "验证失败!";
    }

    }
    }


    private Method getMethdByClassAndName(Class c, String name) {
    Method[] methods = c.getDeclaredMethods();//获取用户声明的方法
    for (Method m : methods) {
    if (m.getName().equals(name))
    return m;
    }
    return null;
    }



    private boolean validateField(ValidatedField[] fields, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    /**field描述的是对参数的要求**/
    for (ValidatedField f : fields) {
    Object arg = args[f.index()];

    //首先判断是否要进行该条件校验
    if (f.notNull() && arg == null) { //判断参数是否为空
    return false;
    } else { //如果该参数能够为空,并且当参数为空时,就不用判断后面的了 ,直接返回true
    if (arg == null)
    return true;
    }

    //
    if (f.maxLen() > 0) { //判断字符串最大长度
    if (((String) arg).length() > f.maxLen())
    return false;
    }

    if (f.minLen() > 0) { //判断字符串最小长度
    if (((String) arg).length() < f.minLen())
    return false;
    }

    if (f.maxValue() != -1) { //判断数值最大值
    if ((Integer) arg > f.maxValue())
    return false;
    }

    if (f.minValue() != -1) { //判断数值最小值
    if ((Integer) arg < f.minValue())
    return false;
    }
    }

    return true;
    }
    }