栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring cloud alibaba 学习(八)OpenFeign中动态代理和方法句柄的结合使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring cloud alibaba 学习(八)OpenFeign中动态代理和方法句柄的结合使用

目录

前言一、接口定义二、创建代理三、创建方法句柄四、测试


前言 在学习OpenFeign的过程中,发现了一个好玩的地方,就是动态代理和方法句柄的结合使用,分别用来处理接口远程方法调用和本地接口默认方法调用。本篇文章对此做一些测试。
一、接口定义

1、实际接口

定义了两个方法,work( )方法需要被代理处理实际的业务,eat( )方法是默认方法,不需要被代理。

public interface People {

    String work();

    default String eat() {
        return "吃饭";
    }
}

2、目标接口

定义了一个类型方法,和一个具体的业务方法

public interface Target {

    Class type();

    String concreteWork();
}

3、目标实现类

public class ConcreteTarget implements Target{

    private final Class type;

    public ConcreteTarget(Class type) {
        this.type = type;
    }

    @Override
    public Class type() {
        return type;
    }

    @Override
    public String concreteWork() {
        System.out.println("程序员写代码...");
        return "编程";
    }

}
二、创建代理

(1)定义两个全局变量

	//代理对象
    public static People proxy;
	//方法句柄
    public static MethodHandle handle;

(2)InvocationHandler

public class CustomInvocationHandler implements InvocationHandler {
    //目标对象
    private Object target;
    
    public CustomInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Object invoke = null;
        //在真实的对象执行之前增强方法
        System.out.println(methodName + ": before invoke。。。");
        if (methodName.equals("work")) {
        	//这里访问实际的业务逻辑,在feign中是访问远程服务端接口
            Method concreteWork = target.getClass().getMethod("concreteWork", null);
            invoke = concreteWork.invoke(target, args);
        } else {
            invoke = "进入了代理方法";
        }
        //在真实的对象执行之后增强方法
        System.out.println(methodName + ": after invoke。。。");
        return methodName + ": " + invoke;
    }

}

(3)创建代理:

 private static void createProxy() {
        //真实对象
        Target target = new ConcreteTarget(People.class);
        //代理对象调用真实对象的方法
        InvocationHandler handler = new InvocationHandlerTest(target);
        
        proxy = (People) Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[]{target.type()}, handler);
    }
三、创建方法句柄

对eat( )方法创建方法句柄

 private static void createMethodHandle() {
        String methodName = "eat";
        try {
            Method defaultMethod = People.class.getMethod(methodName, null);
            Class declaringClass = defaultMethod.getDeclaringClass();
            Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
            field.setAccessible(true);
            MethodHandles.Lookup lookup = (MethodHandles.Lookup) field.get(null);

            MethodHandle unboundHandle = lookup.unreflectSpecial(defaultMethod, declaringClass);
            //绑定代理对象
            handle = unboundHandle.bindTo(proxy);
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
    }
四、测试

1、调用代理对象的work( )方法

String result = proxy.work();
System.out.println(result);

结果:

work: before invoke。。。
程序员写代码...
work: after invoke。。。
work: 编程

可以看出,调用 work( ) 方法进入了代理invoke( )方法。

2、调用代理对象的eat( )方法

String result = proxy.eat();
System.out.println(result);

结果:

eat: before invoke。。。
eat: after invoke。。。
eat: 进入了代理方法

可以看出,调用 eat( ) 方法同样进入了代理invoke( )方法。

3、调用方法句柄

Object result = handle.invokeWithArguments();
System.out.println(result);

结果:

吃饭

可以看出,通过方法句柄方式调用,这样就能动态的访问到接口的默认方法,而不会进入到代理的invoke( )方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/732143.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号