java反射获取方法时,设置方法的参数类型问题?

大家好,请看我的问题描述:

public class Test{

    public void add(String name,String age) {
    //这里需要通过判断Test类中是否有addAfter方法,如果有就执行addAfter(name,age)
    }

    public void addAfter(String name,String age) {
        System.out.println("我执行啦!");
    }

}

如上,当add方法被调用的时候,会去判断当前Test类中是否有addAfter方法(addAfter方法的参数与add的参数是一致的,后期这个判断会放到注解中通过切面来判断)

通过反射获取addAfter的时候需要指定参数类型:

Method methodAddAfter = testClass.getMethod("addAfter",String.class,String.class);

现在的问题是getMethod的后两个参数 String.class,String.class 是动态的(取决于add的参数类型),我想问的是:如何将add的参数类型作为参数传入到testClass.getMethod中去呢?谢谢!🌹


另外,我上面的目的其实就是想为add添加一个后置方法,类似thinkphp中的前置、后置方法:

namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller{
      //前置操作方法
      public function _before_index(){
          echo 'before<br/>';
      }
      public function index(){
          echo 'index<br/>';
      }
      //后置操作方法
      public function _after_index(){
          echo 'after';
      }
} 

那么springboot中有没有什么好的解决方案呢(每个方法自动去匹配:_before_当前方法名、_after_当前方法名)😂

阅读 2.6k
2 个回答

ddAfter方法的参数与add的参数是一致的,既然你前面约定了这个约束,当你调用add方法的时候,aop一拦add方法,参数类型就都有了;

image.png
image.png

如果是直接在 add 里找 afterAdd 来调用,大概应该是这样:

public void add(String name, int age) {
    out.printf("[add] %s (%d)%n", name, age);

    // 下面是查找调用 afterAdd
    var c = getClass();
    try {
        var m = c.getMethod("afterAdd", String.class, int.class);
        m.invoke(this, name, age);
    }
    catch (Exception e) {
        out.println(String.format("[Error] %s", e.getMessage()));
    }
}

getMethod 的时候,知道方法名,也知道参数列表(就是当前 add() 的参数列表)。

如果采用 Annotation 来写,很大概率会有一个管理器,或者调用器。因为 Annotation 需要通过反射去获取。暂且给它命名为 Invoker。

那么 Invoker 在调用 add 的时候,要么是直接调用,这种情况下其参数列表是程序员知道的,所以可以传递这个参数列表去找 afterAdd。这种情况和上面的示例类似。

要么是不知道参数列表,而是通过反射 addMethod 对象去调用,这时候通过 Method.getParameterTypes() 是可以拿到参数列表的。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InvokeAfter {
    String after();
}
Object invoke(T instance, Object... args) throws InvocationTargetException, IllegalAccessException {
    // method 提前取了放在 field 里的
    if (method == null || instance == null) { return null; }
    var result = method.invoke(instance, args);
    invokeAfter(instance, args);
    return result;
}

void invokeAfter(T instance, Object... args) {
    // 通过 method 反射对象去拿 Annotation
    var a = method.getAnnotation(InvokeAfter.class);
    if (a == null) { return; }

    var c = instance.getClass();
    try {
        // 通过 method.getParameterTypes() 拿参数列表
        var m = c.getMethod(a.after(), method.getParameterTypes());
        m.invoke(instance, args);
    }
    catch (Exception e) {
        out.println(e);
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题