简单说说注解到底用在哪了?

本文只简单分析注解的使用,供注解初学者尝试使用,使用过程中还需要自己加强原理追溯;

包含(注解是什么,如何自定义注解,注解作用在那里,如何在开发中使用注解)

 

1、注解是什么?

  官方定义:

  注解(Annotation),也叫元数据。一种代码级别的说明。
what ???? 啥是元数据??

  元数据:描述数据的数据。(举例:我形容某个人,哪身高,体重,肤色,头发等 就是元数据了)

  但是,注解是描述什么的呢?(类, 方法, 属性..)

  常规理解注解就是对指定对象的额外信息指定和约束,但这个指定和约束必须要有监督者,才真正发挥作用。 

  比如:

  
@Target({ElementType.FIELD, ElementType.METHOD})  // 作用对象(FIELD:属性,METHOD:方法 当然还有其他枚举,)
@Retention(RetentionPolicy.RUNTIME) //(运行时生效)
public @interface FieldCanNotNull {
}

 

上面就是一个简单入门的注解,在运行的时候,是有效的,可被获取及解析的。
//测试类
public class Person{

@FieldCanNotNull  //这个注解就是咸鱼
private String merchangNO;

}

 

但是,这个在没有代码解释的时候,毫无意义。

怎么才能让它变得有意义,有价值?
 
那就是通过某种方式 ,可以在运行的时候获取到这个对象的
merchangNO 属性信息,并且获取这个属性的元数据。而 @FieldCanNotNull 就是元数据。
想要获取的话,那就需要通过反射的方式,或者当前类的基础信息,并获取当前属性的注解信息。

    /**
     * 属性非空校验
     * @param object
     * @return
     */
    public static boolean isNull4fields(Object object){
        if (isNull(object)){
            throw NetInException.PARAM_REQUIRED_ERROR.newInstance("object  can not be null");
        }
        List<Field> fields = getAllFields(object.getClass(), new ArrayList<>()); //获取所有属性
        if (CollectionUtils.isEmpty(fields)){
            return false;
        }

        Iterator<Field> iterator = fields.iterator(); //获取迭代器

        Object fieldVal;
        while ( iterator.hasNext()) {
            Field field = iterator.next();
            if ( field.isAnnotationPresent(FieldCanNotNull.class)){ //判断当前属性是否有 FieldCanNotNull 注解
                fieldVal = invokeGetMethod(field.getName(), "", object); //调用当前属性的get 方法获取属性值
                if(isNull(fieldVal)){ //如果当前属性址是空
                    String errMsg = field.getName() + "  can not be null"; //组装信息 抛出异常
                    throw NetInException.PARAM_REQUIRED_ERROR.newInstance(errMsg, null);
                }
            }else{
                continue;
            }

        }
        return false;
    }

   真正有意义就是这一段利用反射,获取属性值,比较注解约束内容。而这个方法的逻辑就是赤裸裸的监督者! 监督被约束的对象是否按照约定进行

所以: 注解是鱼 , 反射解析是水, 两者相辅相成。



好的! 那么咱们进入一个全流程(自定义注解)


1、定义注解(也就是建立法律约束)
2、在将要被约束的对象/方法/属性 上添加注解(法律针对对象)
3、特定的反射功能,获取注解,解析注解并校验 (法律解读,监督者检查是否违背法律)
4、在特定的地方调用反射功能 也就是调用监督者。

开发过程什么情况下使用注解?
  1、有校验需求时
  2、有约束需求时
  3、有隔离了原本业务的非业务功能时 ...

等等,这个感觉有点像AOP的思想啊,没错,我们在使用的过程一般还真的是把这个监督者使用AOP思想来实现。这样就从核心业务上把注解给解析判断喽!
那怎么样呢?还有啥?
既然是AOP那么代理是必然要有的。
  所以最终常用的就是 , 在代理类中 使用反射 前置处理 解析注解 最后调用目标方法;

例如下面:使用Spring实现AOP 在调用方法之前,进行前置注解解析和处理

前置处理(AOP)
@Aspect
public class VerifyAop {

    /**
     * 校验参数
     * @param joinPoint
     * @throws Throwable
     */
    public void verifyMethod(JoinPoint joinPoint) throws Throwable {

        Object[] args = joinPoint.getArgs();
        for (Object arg:args){
            VerifyUtil.isNull4fields(arg);
        }
    }

    /**
     * 环绕处理
     * @param point
     * @return
     * @throws Throwable
     */
    public Object exeMethod(ProceedingJoinPoint point) throws Throwable {
        return point.proceed();
    }

}

 

校验方法(监督者)
public class VerifyUtil {
    private VerifyUtil(){};

    /**
     * 校验参数为否为空
     * @param param
     * @param paramDesc 参数名
     */
    public static void validateNotEmptyParam(Object param, String paramDesc){
        if (param == null){
            throw  NetInException.PARAM_REQUIRED_ERROR.newInstance(paramDesc + "为必填项");
        }

        if ((param instanceof Map && MapUtils.isEmpty((Map)param))
                || (param.getClass().isArray() && ArrayUtils.getLength(param) ==0)
                || (param instanceof CollectionUtils && CollectionUtils.isEmpty((Collection)param))
                || (param instanceof String && StringUtils.isEmpty(((String)param).trim()))){

            throw  NetInException.PARAM_VALIDATE_ERROR.newInstance(paramDesc + "不能为空");
        }
    }

    /**
     * 判断对象是否为空
     * @param object
     * @return
     */
    public static boolean isNull(Object object){
        if (object==null){
            return true;
        }else if (StringUtils.isEmpty(object.toString())){
            return true;
        }
        return false;
    }
/**
     * 属性非空校验
     * @param object
     * @return
     */
    public static boolean isNull4fields(Object object){
        if (isNull(object)){
            throw NetInException.PARAM_REQUIRED_ERROR.newInstance("object  can not be null");
        }
        List<Field> fields = getAllFields(object.getClass(), new ArrayList<>()); //获取所有属性
        if (CollectionUtils.isEmpty(fields)){
            return false;
        }

        Iterator<Field> iterator = fields.iterator(); //获取迭代器

        Object fieldVal;
        while ( iterator.hasNext()) {
            Field field = iterator.next();
            if ( field.isAnnotationPresent(FieldCanNotNull.class)){ //判断当前属性是否有 FieldCanNotNull 注解
                fieldVal = invokeGetMethod(field.getName(), "", object); //调用当前属性的get 方法获取属性值
                if(isNull(fieldVal)){ //如果当前属性址是空
                    String errMsg = field.getName() + "  can not be null"; //组装信息 抛出异常
                    throw NetInException.PARAM_REQUIRED_ERROR.newInstance(errMsg, null);
                }
            }else{
                continue;
            }

        }
        return false;
    }
/** *获取当前类及当前类的多层父类属性集合 * @param clazz * @param fields * @return */ public static List<Field> getAllFields(Class clazz,List<Field> fields ){ Field[] declaredFields = clazz.getDeclaredFields(); Class superclass = clazz.getSuperclass(); if (superclass == null || "Object".equals(superclass.getSimpleName())){ fields.addAll(Lists.newArrayList(declaredFields)); return fields; }else { List<Field> fieldsList = Arrays.asList(declaredFields); fields.addAll(fieldsList); getAllFields(superclass, fields); } return fields; } /** * 调用指定对象的getXX 方法(用于获取某个对象的某个属性的值) * @param fieldName * @param suffix * @param object * @return */ private static Object invokeGetMethod(String fieldName, String suffix, Object object ) { Method mget = ReflectionUtils.findMethod(object.getClass(), "get" + StringUtils.capitalize(fieldName) + StringUtils.trimToEmpty(suffix)); return ReflectionUtils.invokeMethod(mget, object); } }

 













posted @ 2018-09-20 17:06  白壮丽  阅读(700)  评论(0编辑  收藏  举报