利用动态代理动态的为接口生成实现类

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();
  }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值