案例:参数填写默认值【注解+JDK动态代理】

学如逆水行舟,不进则退~
今天记录一个小案例:当一个实例调用一个有参方法的时候,判断该参数是否为NULL,如果是NULL则给一个默认值。

1、定义一个校验是否为NULL并且给定默认值的参数

package com.dongzi;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface CheckParam {

    /**
     * 是否必填参数
     */
    boolean required() default false;

    /**
     * 默认值
     */
    String defaultValue() default "";
}

2、定义一个为实现一个代理的统一行为人接口

package com.dongzi;

/**
 * 定义一个被代理的统一行为人
 */
public interface People {

    /**
     * 所有人都具备讲话的能力
     */
    void say(String saySomething);
}

3、定义一个实现该行为方式的学生类

package com.dongzi;

/**
 * 被代理的对象
 */
public class Student implements People {

    @Override
    public void say(@CheckParam(required = true, defaultValue = "再见,小哥哥~~") String saySomething) {
        System.out.println("To Talk:" + saySomething);
    }
}

4、定义一个动态代理对象

package com.dongzi;

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

/**
 * 统一行为人的被代理类实现
 */
public class PeopleInvocationHandlerImpl implements InvocationHandler {

    /**
     * 代理对象
     */
    private final Object proxyObj;

    public PeopleInvocationHandlerImpl(Object proxyObj) {
        this.proxyObj = proxyObj;
    }

    /**
     * @param proxy  代理类实例
     * @param method 代理方法
     * @param args   参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Class<?> proxyObjClass = this.proxyObj.getClass();
        Method[] methods = proxyObjClass.getMethods();
        Method myMethod = null;
        for (Method m : methods) {
            if (m.getName().equals(method.getName())) {
                myMethod = m;
                break;
            }
        }
        if (myMethod != null) {
            /*
            Annotation[i][j]
                i: 参数列表中第i个参数
                j: 第i个参数中的第j个注解
             */
            Annotation[][] annotations = myMethod.getParameterAnnotations();
            if (annotations.length > 0) {
                for (int i = 0; i < annotations.length; i++) {
                    for (int j = 0; j < annotations[i].length; j++) {
                        Annotation anno = annotations[i][j];
                        if (anno instanceof CheckParam) {
                            // 参数检查的注解
                            if (((CheckParam) anno).required()) {
                                String defaultValue = ((CheckParam) anno).defaultValue();
                                // 对第i个参数并且符合参数检查的注解进行赋默认值
                                // TODO:这里需要注意一下问题,方便测试使用的String类型参数,如果多个参数的话,类型也要为String,其他类型没有考虑,否则会因为参数类型不一致而无法正常执行invoke方法
                                args[i] = (null == args[i] || "".equals(args[i])) ? defaultValue : args[i];
                            }
                            // TODO: 符合其他参数上的注解 if()
                        }
                    }
                }
            }
        }
        // 执行被代理类的方法
        // args参数类型必须全部匹配否则异常无法执行invoke反射到对应方法执行
        return method.invoke(this.proxyObj, args);
    }
}

5、主程序

package com.dongzi;

import java.lang.reflect.Proxy;

/**
 * 主程序
 */
public class Main {


    public static void main(String[] args) {

        // 确定被代理的对象
        Student student = new Student();
        PeopleInvocationHandlerImpl handler = new PeopleInvocationHandlerImpl(student);
        /*
        创建一个代理的实例对象:
            创建代理对象必须要符合实现了同一个标准的接口 且 被代理对象只能把类型强制转换为接口
         */
        People studentProxyObj = (People) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), handler);

        // 被代理之后,执行方法
        studentProxyObj.say("你好,小哥哥~~"); // 输出:To Talk:你好,小哥哥~~
        studentProxyObj.say(null); // 输出结果:To Talk:再见,小哥哥~~
    }
}

6、执行结果

    两次调用say()方法的结果:第一次调用传入参数,参数正常打印;第二次传入NULL,正常来说会打印NULL值,而不是输出一段描述,但是因为加了注解并给定默认值,所以会打印出defaultValue的值,而并不是NULL。
案例:参数填写默认值【注解+JDK动态代理】_第1张图片

附1:项目结构
案例:参数填写默认值【注解+JDK动态代理】_第2张图片

附2:一些关于JDK动态代理和注解

  • Java Reflect - 利用反射获取方法参数上的注解
  • Java JDK 动态代理(AOP)使用及实现原理分析

你可能感兴趣的:(#,java,java,动态代理,注解)