最近更新light-dao遇到的。

需要在一个接口中增加default方法,同时需要对非default方法重写。

大概类似这样:

public interface BaseDao {

default String getName() {

return "name";

}

@Select("select * from ad")

List getAll();

}

我们重写的Handler类似这样:

public class DaoInvocationHandler implements InvocationHandler {

private Map sqlExecutorMap = new ConcurrentHashMap();

private DataSourceHolder dataSourceHolder;

public DaoInvocationHandler(DataSourceHolder dataSourceHolder) {

this.dataSourceHolder = dataSourceHolder;

}

//对应于Dao接口里的函数

//将每一个函数映射为一个SqlExecutor

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if (!sqlExecutorMap.containsKey(method)) {

synchronized (method) {

if (!sqlExecutorMap.containsKey(method)) {

SqlExecutor sqlExecutor = new SqlExecutor.Builder(method, dataSourceHolder.getLightTemplate()).build();

sqlExecutorMap.put(method, sqlExecutor);

}

}

}

return sqlExecutorMap.get(method).execute(args);

}

}

我们需要对default方法做特殊处理,搜索了一下stackoverflow

里面提供了一种解决方式:

Object result = MethodHandles.lookup()

.in(method.getDeclaringClass())

.unreflectSpecial(method,method.getDeclaringClass())

.bindTo(target)

.invokeWithArguments();

但是在使用时,报错如下:

Caused by: java.lang.IllegalAccessException: no private access for invokespecial

又尝试了几次,发现这种方式的改进版:

Constructor constructor = MethodHandles.Lookup.class

.getDeclaredConstructor(Class.class, int.class);

constructor.setAccessible(true);

Class> declaringClass = method.getDeclaringClass();

int allModes = MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE;

return constructor.newInstance(declaringClass, allModes)

.unreflectSpecial(method, declaringClass)

.bindTo(proxy)

.invokeWithArguments(args);

通过设置constructor.setAccessible(true);来解决access权限问题。目前来看,问题基本解决。最终的invocationHandler代码如下:

public class DaoInvocationHandler implements InvocationHandler {

private Map sqlExecutorMap = new ConcurrentHashMap();

private DataSourceHolder dataSourceHolder;

public DaoInvocationHandler(DataSourceHolder dataSourceHolder) {

this.dataSourceHolder = dataSourceHolder;

}

//对应于Dao接口里的函数

//将每一个函数映射为一个SqlExecutor

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//default方法不重写

if (method.isDefault()) {

Constructor constructor = MethodHandles.Lookup.class

.getDeclaredConstructor(Class.class, int.class);

constructor.setAccessible(true);

Class> declaringClass = method.getDeclaringClass();

int allModes = MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE;

return constructor.newInstance(declaringClass, allModes)

.unreflectSpecial(method, declaringClass)

.bindTo(proxy)

.invokeWithArguments(args);

} else if (!sqlExecutorMap.containsKey(method)) {

synchronized (method) {

if (!sqlExecutorMap.containsKey(method)) {

SqlExecutor sqlExecutor = new SqlExecutor.Builder(method, dataSourceHolder.getLightTemplate()).build();

sqlExecutorMap.put(method, sqlExecutor);

}

}

}

return sqlExecutorMap.get(method).execute(args);

}

}

虽然解决了问题,但还是觉得java 8应该在method里添加针对interface default方法的直接调用方式,这样绕一大圈的解决方式显然不够优雅。

只能期待reflect api下个版本的修改了。

java接口中的default_java8 通过反射执行接口的default方法相关推荐

  1. java 拦截器顺序_Springmvc拦截器执行顺序及各方法作用详解

    实现HandlerInterceptor接口或者继承HandlerInterceptor的子类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInt ...

  2. 通过反射执行get、set方法

    Class clazz = sourceObj.getClass(); 1.获取所有属性 BeanInfo beanInfo = Introspector.getBeanInfo(clazz); Pr ...

  3. Java default 方法

    Default 方法 前言:当我在用Spring boot框架开发项目中配置Webconfig类时,该类实现了WebMvcConfigurerAdapter抽象类.但是IDE提示WebMvcConfi ...

  4. java 反射执行语句_JAVA反射机制

    JAVA反射机制定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的 ...

  5. java调用一个方法后怎么继续执行不等待该方法的返回_Java面试题大全2020版(二)...

    今天给大家推送第二部分,主要的大块内容分为:多线程.反射.对象拷贝.三大块内容中涉及到的考点如下: 三.多线程 35. 并行和并发有什么区别? 并行是指两个或者多个事件在同一时刻发生:而并发是指两个或 ...

  6. 【Android NDK 开发】JNI 线程 ( JNI 线程创建 | 线程执行函数 | 非 JNI 方法获取 JNIEnv 与 Java 对象 | 线程获取 JNIEnv | 全局变量设置 )

    文章目录 I . JNI 线程创建 II . 线程执行函数 III . 线程方法获取 Java 对象 IV . 线程方法获取 JNIEnv V . JNI 线程 完整代码示例 I . JNI 线程创建 ...

  7. 深入理解Java类型信息(Class对象)与反射机制

    关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java并发之synchronize ...

  8. java display.getdefault()_java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

  9. Java提高班(六)反射和动态代理(JDK Proxy和Cglib)

    反射和动态代理放有一定的相关性,但单纯的说动态代理是由反射机制实现的,其实是不够全面不准确的,动态代理是一种功能行为,而它的实现方法有很多.要怎么理解以上这句话,请看下文. 一.反射 反射机制是 Ja ...

最新文章

  1. 《2021全球脑科学发展报告》发布
  2. git-svn:通过git来管理svn代码
  3. 查看临界区等待线程数量
  4. 老男孩教育Python 9期第一课练习题答案
  5. 【NLP】NLP提效,除了选择合适的模型,就是数据增强了
  6. Html table 实现Excel多格粘贴
  7. 为什么一直没有意识到自己还是面向过程编程
  8. 2018-3-28Linux系统管理(16)计算机网络基础
  9. Java工程师必备技能
  10. web-java-Java Concurrency Utilities
  11. 自定义数字格式字符串_部分分隔符和条件格式
  12. 练习题︱基于今日头条开源数据(二)——两款Apriori算法实践
  13. 解读【ICLR2020】多伦多大学:基于策略网络的探索模型规划
  14. ASP.NET profile之 找不到存储过程'dbo.aspnet_CheckSchemaVersion'
  15. shell倒数第三位增加字符_shell中常用的变量处理、字符串操作(之三)
  16. humid vs wet vs moist
  17. Redis的DMS管理工具treeNms
  18. 【1】EFR32配置433Mhz(可通信CC1101)——EFR32 项目例程打开和烧录
  19. 在格式化字符串的边缘试探
  20. php 多个一维数组合拼成二维数组的方法

热门文章

  1. Leetcode-Pascal's Triangle
  2. 从0开始学Swift笔记整理(五)
  3. [PHP] - Laravel - CSRF token禁用方法与排除验证csrf_token的url设置
  4. 将php分页类YII绑定框架,就需要改变风格的基础
  5. x86_64的debian(wheezy)下使用qemu和busybox运行linux
  6. python open w_python-文件操作示例
  7. Ubuntu18.04修改主机名和用户名
  8. Linux基于v4l2的视频采集(可用)
  9. 显示编译代码时长的demo
  10. C++之判断当前是debug还是realease