欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

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

时间:2023-07-06
目录

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


前言 在学习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( )方法。

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。