业务场景
在一个线程中,需要使用反射的方式去调用某个类的方法,如:
String randomStr = "ugefqbfl";
//获取类对象
Class clazz = Class.forName("com.xxx.Test");
//实例化对象
Object o = clazz.newInstance();
//获取想要执行的方法
Method execute = clazz.getDeclaredMethod("execute", String.class);
//执行方法
execute.invoke(o, "param");
//其他操作...
如果想把 randomStr 参数传到反射方法中使用,如:
//获取想要执行的方法
Method execute = clazz.getDeclaredMethod("execute", String.class, String.class);
//执行方法
execute.invoke(o, "param", randomStr);
如果是直接传参,通用性不高,随着后续业务的发展可能要传入更多的参数,这样就要一直修改多出,耦合也高。因为反射这些操作我的业务场景都是在一个异步线程中执行,所以我考虑通过 ThreadLocal 来传递参数。
实现方法
- 我们先定义一个上下文类,如TaskContext:
public class TaskContext implements AutoCloseable {
static final ThreadLocal<Map<String, String>> ctx = new ThreadLocal<>();
public TaskContext(String randomStr) {
Map<String, String> map = new HashMap<>();
map.put("randomStr", randomStr);
ctx.set(map);
}
public static String getRandomStr() {
return ctx.get().get("randomStr");
}
@Override
public void close() {
ctx.remove();
}
}
这里实现了一个接口 AutoCloseable 自动关闭,是为了在方法执行完以后,将线程的上下文内容清空。因为一般线程都是在线程池中使用,如果没有清空内容,线程复用的时候会把上次的状态变量带到本次的执行中。
- 原来的场景加上上下文
try (TaskContext ctx = new TaskContext()) {
String randomStr = "ugefqbfl";
//获取类对象
Class clazz = Class.forName("com.xxx.Test");
//实例化对象
Object o = clazz.newInstance();
//获取想要执行的方法
Method execute = clazz.getDeclaredMethod("execute", String.class);
//执行方法
execute.invoke(o, "param");
//其他操作...
}
在 try() 中实例化 TaskContext ,会在方法执行完成后自动调用实现 AutoCloseable 接口的 close() 方法,不管你有没有声明 finally 。
- 反射方法中使用
public class Test {
public void execute(String param) {
String randomStr = TaskContext.getRandomStr();
...
}
}
可以直接通过 TaskContext 的静态方法获取到 randomStr 参数。
以上,这样就完成了单线程内的反射方法传参。