如何避开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声明。
Map res = (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
关注公众号:
微信赞赏
支付宝赞赏
