智慧·快乐·成长——科技造福于人。

如何避开java的动态代理用反射机制优雅地解耦

daili
基于java反射机制实现的动态代理总是在调用代码里带着被代理类的小尾巴,比如:UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler); 这里的UserService就是被代理类的接口,既然要封装被代理类的内部实现,那么还要拿他们的接口类写到主调方代码里就不干不净了,主调方每次调用时都要考虑被代理方有没有变更,变更了还要改调用逻辑,着实鸡肋。下面的代码提供一种完全封装被代理类的演示方案,调用方在代码层面不需要使用被代理类的接口来接收返回,这就给调用方和被调用方实现了解耦,双方仅通过必要的声明和输入输出参数通信,最大限度降低代码级的噪声。想想你用的Feign多恶心!

/*
 * Copyright 2019-2099 the original author or authors.
 * Copyright (c) 2021, 智乐兔 - .com. All rights reserved.
 */
package com..collect.util;

import .lang.reflect.InvocationTargetException;
import .lang.reflect.Method;
import .util.HashMap;
import .util.Map;

/**   
 * @Title: InvokeProxy. 
 * @Package com..collect.util 
 * @Description: 一个调用代理,可以通过事先声明的类路径名、方法名和入参调用目标对象。
 * @author .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..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                
        }
}

转载请注明:转自《如何避开java的动态代理用反射机制优雅地解耦
本文地址:https://www..com/archives-10776.html

赞赏

微信赞赏支付宝赞赏

上一篇
下一篇

相关文章

在线留言

你必须 登录后 才能留言!