学如逆水行舟,不进则退~
今天记录一个小案例:当一个实例调用一个有参方法的时候,判断该参数是否为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。
附1:项目结构
附2:一些关于JDK动态代理和注解