Ijava中的反射需要一个实例,但是接口无法提供这样的实例,但是JDK提供了一个叫做动态代理的东西,这个代理恰恰只能代理接口。所以我们想要反射接口需要使用这个动态代理来做。
在java的动态代理机制中,有两个重要的东西,一个是 InvocationHandler(接口)、另一个则是 Proxy(类),这是我们动态代理必须用到的两个东西。
首先创建一个接口(以studentMapper为例,其中提供了一个根据ID获取student对象的方法):
public interface StudentMapper{
/**
* 根据id查对象
*/
Student selectById(@Param("id") Integer id);
}
现在如果我们需要反射使用该接口根据学生ID获取学生对象是无法直接反射调取的,所以我们需要一个动态代理类,下面创建一个MyInvocationHandler,需要实现上面说的InvocationHandler接口:
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target,args);
}
}
其中该类设置了一个target属性,该属性即为需要代理的接口对象,也就是studentMapper,还提供了一个需要一个参数的构造函数。
自此,我们的代理工作基本做完,现在需要调用一下这个代理类
try{
Class interfaceImpl = Class.forName("StudentMapper");//这里要写全类名
Object instance = Proxy.newProxyInstance(
interfaceImpl.getClassLoader(),
new Class[]{interfaceImpl},
new MyInvocationHandler(sqlSession.getMapper(interfaceImpl))
);
Method method = instance.getClass().getMethod("selectById", Integer.class);
method.invoke(instance,2);
}catch(Exception e){
e.printStackTrace();
}
这里需要注意,newProxyInstance()方法中最后一个参数,即为我们创建的动态代理的类(因为我这里调用的接口为mybatis中mapper中的接口,所以需要从sqlSession中getMapper).
最后得到该Mapper的接口之后反射调用selectById方法即可。