Jdk动态代理如何处理java8接口的default方法

Jdk动态代理如何处理java8接口的default方法:
MethodHandlesUtil工具类参考我的另一篇博客: java8中实现调用对象的父类方法

我们在使用Jdk的动态代理时,一定会写一个java.lang.reflect.InvocationHandler实现类,用来处理编写后续的处理逻辑,或者根据方法名写相应的逻辑代码。该接口方法invoke(Object proxy, Method method, Object[] args)有三个参数,
proxy是JDK动态生成的接口实现类Class实例化的对象。
method是当前正在被调用的接口方法,
args则是方法参数。
对于JDK的动态代理来说,我们是不能在InvocationHandler中直接反射调用proxy对象方法的.因为其方法实现就是通过InvocationHandler实现,会造成无限死循环调用InvocationHandler中的invoke方法. 那么如果接口中含有java8 中default关键字定义的默认方法,是否存在同样的问题. 下面看下实验代码:
接口类如下:
getAddress是一个普通的接口方法, getUserName是个default方法, 实现类即使不重写该方法也是能直接被调用的.

public interface UserMapper {
    
    
    public static final Logger logger = LoggerFactory.getLogger(UserMapper.class);

    String getAddress(String userId);

    default String getUserName(String userName, Boolean yes, int age) {
    
    
        logger.info("bruce");
        return "bruce " + userName + " " + yes + " " + age;
    }
}

实现动态代理以及测试类

public class MainTest {
    
    
    static class MyInvocationHandler implements InvocationHandler {
    
    

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
            return method.invoke(proxy, args);
        }
    }
    
    public static void main(String[] args) {
    
    

        UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(UserServiceInvoke.class.getClassLoader(),
                new Class[]{
    
    UserMapper.class}, new MyInvocationHandler());

        //String address = userMapper.getAddress("12345");
        //System.out.println(address);

        //调用含有default关键字的方法
        String userName = userMapper.getUserName("aa", true, 18);
        System.out.println(userName);
    }
}

运行结果: 实际上跟普通接口方法一样,都是不能在invoke方法中直接调用的.
在这里插入图片描述
那么JDK的动态代理,如何能够调用接口中定义的default方法呢?
那就是使用java7开始提供的方法句柄MethodHandle,调用对象的父类方法,参考我的另一篇博客: java8中实现调用对象的父类方法
实现代码如下:

public class MyInvocationHandler implements InvocationHandler {
    
    
    private static final Logger logger = LoggerFactory.getLogger(MyInvocationHandler.class);

    private ConcurrentHashMap<Method, MethodHandle> methodHandleMap = new ConcurrentHashMap<>();

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        if (method.isDefault()) {
    
    
            MethodHandle defaultMethodHandle = methodHandleMap.computeIfAbsent(method, key -> {
    
    
                MethodHandle methodHandle = MethodHandlesUtil.getSpecialMethodHandle(method);
                return methodHandle.bindTo(proxy);
            });
            logger.info("default 接口方法:{}", method.getName());
            return defaultMethodHandle.invokeWithArguments(args);
        }

        logger.info("普通接口方法:{}", method.getName());
        //做其他逻辑处理,

        //模拟数据
        return "这是一个普通接口方法:" + method.getName();
    }
}
public class MainTest {
    
    

    public static void main(String[] args) {
    
    

        UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(UserServiceInvoke.class.getClassLoader(),
                new Class[]{
    
    UserMapper.class}, new MyInvocationHandler());

        String address = userMapper.getAddress("12345");
        System.out.println(address);

        System.out.println();

        String userName = userMapper.getUserName("aa", true, 18);
        System.out.println(userName);
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u013202238/article/details/108692175