最近看了Feign的远程调用代理这部分的代码,尝试的自己写了一下。
调用模型图:
1.ProxyMethod注解,判断方法是否需要做代理。
/** * 代理方法注解 */@java.lang.annotation.Target(METHOD)@Retention(RUNTIME)public @interface ProxyMethod { public String value();}
2.启动类,idService是生成的代理类。
public class StartApplication { public static void main(String[] args) { // 创建代理 IdService idService = ProxyUtil.newInstance(new Target.HardCodedTarget<>(IdService.class)); // 执行代理方法 Integer id = idService.getId(); System.out.println(id); }}
3.IdService服务类
public interface IdService { @ProxyMethod("getId") public Integer getId();}
4.类代理
/** * 代理 * @param*/public interface Target { public Class type(); public static class HardCodedTarget implements Target { private Class type; public HardCodedTarget(Class type) { this.type = type; } @Override public Class type() { return type; } }}
5.代理工具类
/** * 代理工具类 */public class ProxyUtil { public staticT newInstance(Target target) { Map nameToHandler = MethodHandler.FactoryMethodHandler.apply(target); Map methodToHandler = new LinkedHashMap (); for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { continue; } else if (isDefault(method)) { MethodHandler.DefaultMethodHandler handler = new MethodHandler.DefaultMethodHandler(method); methodToHandler.put(method, handler); } else { System.out.println("ProxyUtil.newInstance.Method:" + method.getName()); methodToHandler.put(method, nameToHandler.get(configKey(target.type(), method))); } } InvocationHandler handler = new DefaultInvocationHandler(target, methodToHandler); @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class []{target.type()}, handler); return proxy; } public static String configKey(Class targetType, Method method) { StringBuilder builder = new StringBuilder(); builder.append(targetType.getSimpleName()); builder.append('#').append(method.getName()).append('('); for (Type param : method.getGenericParameterTypes()) { builder.append(getRawType(param)).append(','); } if (method.getParameterTypes().length > 0) { builder.deleteCharAt(builder.length() - 1); } return builder.append(')').toString(); } public static String getRawType(Type param) { return param.getTypeName(); } /** * Identifies a method as a default instance method. */ public static boolean isDefault(Method method) { // Default methods are public non-abstract, non-synthetic, and non-static instance methods // declared in an interface. // method.isDefault() is not sufficient for our usage as it does not check // for synthetic methods. As a result, it picks up overridden methods as well as actual default methods. final int SYNTHETIC = 0x00001000; return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) == Modifier.PUBLIC) && method.getDeclaringClass().isInterface(); } /** * 自定义方法代理 */ public static class DefaultInvocationHandler implements InvocationHandler { private final Target target; private final Map dispatch; public DefaultInvocationHandler(Target target, Map dispatch) { this.target = target; this.dispatch = dispatch; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("equals".equals(method.getName())) { try { Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; return equals(otherHandler); } catch (IllegalArgumentException e) { return false; } } else if ("hashCode".equals(method.getName())) { return hashCode(); } else if ("toString".equals(method.getName())) { return toString(); } return dispatch.get(method).invoke(args); } @Override public boolean equals(Object obj) { if (obj instanceof DefaultInvocationHandler) { DefaultInvocationHandler other = (DefaultInvocationHandler) obj; return target.equals(other.target); } return false; } @Override public int hashCode() { return target.hashCode(); } @Override public String toString() { return target.toString(); } }}
6.代理方法处理类
public interface MethodHandler { Object invoke(Object[] argv) throws Throwable; public static class DefaultMethodHandler implements MethodHandler { private final MethodHandle unboundHandle; private MethodHandle handle; public DefaultMethodHandler(Method defaultMethod) { try { Class declaringClass = defaultMethod.getDeclaringClass(); Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); field.setAccessible(true); MethodHandles.Lookup lookup = (MethodHandles.Lookup) field.get(null); this.unboundHandle = lookup.unreflectSpecial(defaultMethod, declaringClass); } catch (NoSuchFieldException ex) { throw new IllegalStateException(ex); } catch (IllegalAccessException ex) { throw new IllegalStateException(ex); } } /** * Bind this handler to a proxy object. After bound, DefaultMethodHandler#invoke will act as if it was called * on the proxy object. Must be called once and only once for a given instance of DefaultMethodHandler */ public void bindTo(Object proxy) { if (handle != null) { throw new IllegalStateException("Attempted to rebind a default method handler that was already bound"); } handle = unboundHandle.bindTo(proxy); } /** * Invoke this method. DefaultMethodHandler#bindTo must be called before the first * time invoke is called. */ @Override public Object invoke(Object[] argv) throws Throwable { if (handle == null) { throw new IllegalStateException("Default method handler invoked before proxy has been bound."); } return handle.invokeWithArguments(argv); } } public static class FactoryMethodHandler { public static Mapapply(Target target) { System.out.println("初始化代理>>>"); Map result = new LinkedHashMap (); Class targetType = target.type(); for (Method method : targetType.getMethods()) { if (method.getDeclaringClass() == Object.class || (method.getModifiers() & Modifier.STATIC) != 0 || ProxyUtil.isDefault(method)) { continue; } result.put(ProxyUtil.configKey(targetType, method), new ProxyMethodHandler(method)); } return result; } } public static class ProxyMethodHandler implements MethodHandler { private Method method; public ProxyMethodHandler(Method method) { this.method = method; } @Override public Object invoke(Object[] argv) throws Throwable { System.out.println("执行代理方法>>>"); ProxyMethod proxyMethod = method.getAnnotation(ProxyMethod.class); if (null != proxyMethod) { if ("getId".equals(proxyMethod.value())) { return 1; } } return null; } }}
在ProxyMethodHandler方法的invoke方法中,根据ProxyMethod注解来处理代理方法的业务逻辑。
作者:
声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接。