1.为什么会有这样的想法去生成接口的实现类
在学习mybatis的过程中,其存在一种机制,接口式编程。利用接口对我们sql的查询进行约束
我们只是写了接口,mybatis能给我们返回一个该接口的实例,这个实例是怎么来的?
思考:由于我们没有写该接口的实现类,mybatis返回的对象肯定不是简单的动态代理
但是我们打印其返回对象的class发现
class com.sun.proxy.$Proxy0
可以看出其就是jdk的动态代理对象。
2.实现动态的为接口生成实现类
我们利用jdk的动态代理,来对接口进行实现。
传统的使用动态代理的方式,需要传入一个被代理类来进行动态代理
我们这里由于没有接口实现类所以我们在写InvocationHandler的实现类的时候,不为其内部添加实现类。
代码如下:
要生成实现类的接口
public interface Person {
public void showName();
public void saying();
}
InvocationHandler的实现类,内部没有上面接口的实现类,也就是没有被代理类
public class InvokeHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// object的公用方法直接调用当前invoke对象的。
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
// 针对接口的不同方法书写我们具体的实现
} else if ("showName".equals(method.getName())) {
System.out.println("张三");
} else if ("saying".equals(method.getName())) {
System.out.println("我叫张三");
}
return null;
}
}
测试:
public static void main(String[] args) {
Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class}, new InvokeHandler());
person.showName();
person.saying();
System.out.println(person);
System.out.println(person.getClass());
}
张三
我叫张三
toString
D.InvokeHandler@6bc7c054
class com.sun.proxy.$Proxy0
这样我们就动态的简单的生成了一个接口的实现类。其原理还是动态代理,只是抛弃掉了被代理类
3.总结
mybaties内部动态的生成接口的实现类,其基本原理就是是如上面的代码所展示
可以去看其MapperProxy的源码:
public class MapperProxy<T> implements InvocationHandler, Serializable {
// 可以看出内部字段是没有被代理类的
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
throws Throwable {
final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
.getDeclaredConstructor(Class.class, int.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
final Class<?> declaringClass = method.getDeclaringClass();
return constructor
.newInstance(declaringClass,
MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
/**
* Backport of java.lang.reflect.Method#isDefault()
*/
private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
&& method.getDeclaringClass().isInterface();
}
}