如何避开java的动态代理用反射机制优雅地解耦
基于java反射机制实现的动态代理总是在调用代码里带着被代理类的小尾巴,比如:UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler); 这里的UserService就是被代理类的接口,既然要封装被代理类的内部实现,那么还要拿他们的接口类写到主调方代码里就不干不净了,主调方每次调用时都要考虑被代理方有没有变更,变更了还要改调用逻辑,着实鸡肋。下面的代码提供一种完全封装被代理类的演示方案,调用方在代码层面不需要使用被代理类的接口来接收返回,这就给调用方和被调用方实现了解耦,双方仅通过必要的声明和输入输出参数通信,最大限度降低代码级的噪声。想想你用的Feign多恶心!
/* * Copyright 2019-2099 the original author or authors. * Copyright (c) 2021, 智乐兔 - zhiletu.com. All rights reserved. */ package com.zhiletu.collect.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * @Title: InvokeProxy.java * @Package com.zhiletu.collect.util * @Description: 一个调用代理,可以通过事先声明的类路径名、方法名和入参调用目标对象。 * @author zhiletu.com * @date 2021年2月5日 * @version V1.0 */ public class InvokeProxy{ private Object excuter; private Method method; private Object[] args; /** * @Title: 初始化代理请求 * @Description: 开一个大后门 * @param classFullName * @param methodName * @param args * @param parameterTypes * @throws ClassNotFoundException * @throws SecurityException * @throws NoSuchMethodException * @throws InstantiationException * @throws IllegalAccessException */ public InvokeProxy(String classFullName, String methodName, Object[] args, Class>[] parameterTypes) throws ClassNotFoundException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException { if (this.getClass().getSimpleName().equalsIgnoreCase(classFullName)) { throw new RuntimeException("不能自己调用自己!"); } Class> clazz = Class.forName(classFullName); this.method = clazz.getMethod(methodName, parameterTypes); this.excuter = clazz.newInstance(); // 此方法对应构造器,调用目标时必须实现对应的构造方法,无参数时对应无参构造,代理目标必须实现无参构造。 // clazz.getClass()返回的是静态区的class对象仅能访问其静态元素(如static方法),而非静态资源只能实例化以后在实例区通过实例对象引用拿到。 this.args = args; } public Object invoke() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (null != this.excuter && null != this.method) { return this.method.invoke(this.excuter, this.args); } else { throw new RuntimeException("请先正确初始化……"); } } public static void main(String[] args){ InvokeProxy proxy = null; try { proxy = new InvokeProxy("com.zhiletu.collect.util.Rand", "getRandCustom", new Object[] {12}, new Class[] {int.class}); } catch (SecurityException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } try { Object result = proxy.invoke(); // 调用方知道返回类型,知道调用目标的名称、类型和参数,就可以通过声明发起调用并正确接收返回值, // 而调用目标的具体实现逻辑得到了封装,这就相当于实现了钩子应用,只不过钩子是对java bean声明。 Mapres = (Map ) result; System.out.println(res); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } class Rand { public Rand() {} /** * @description num是10的整数倍 * @param num * @return * @throws Exception */ public static long getRand(int num) throws Exception { if (num <= 0 && num % 10 != 0) { throw new Exception("必须是10的正整数倍!"); } double d = Math.random()*10; // 1~10的随机数 return Math.round(d * num); // 3位long } /** * @description 任意整数范围内的随机数 * @param num * @return * @throws Exception */ public static Map getRandCustom(int num) throws Exception { if (num <= 0) { throw new Exception("必须是正整数!"); } double d = Math.random()*num; // 1~10的随机数 Map map = new HashMap (); map.put("round", Long.valueOf(Math.round(d))); return map; // 3位long } }
声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 嗅谱网
转载请注明:转自《如何避开java的动态代理用反射机制优雅地解耦》
本文地址:http://www.xiupu.net/archives-10776.html
关注公众号:
微信赞赏
支付宝赞赏