java中通过反射获取方法并且调用(getMethod和invoke深入)实践
为了支持业务的快速变更,往往采用可配置的方式,将业务逻辑的处理部分配置在数据库中或者XMl文件里。配置什么,如何配置才更灵活,That's a problem.
以数据库配置为例(xml相同),在数据库中可以配置上java包名+类名,一个类只处理一个功能(符合设计模式中的单一性原则),这样只需要把数据库中的类名读出来,Class.forname("xxxx").newInstance()即可实现,这种方式简单,但会产生大量.java文件,管理一下还是挺麻烦的,并且每个.java文件处理一个单一的功能(即便功能很简单,也会生成一个.java文件),个人觉得有点浪费,并且每个.java文件肯定会有部分重复的地方(如属性变量等),当然如果不嫌烦的话,可以将功能的抽象出来,每写个.java都看下是否需要抽象,无穷尽也!本文讨论的不是这种方式配置,采用配置函数的方式,并且运行配置的函数,来达到相同的目的。
1、先看下我们拥有的函数:
package com.java.reflect; public class ConvertFunction implements IFunction { public final int PRE_ARGS_NUM = 2; //默认参数个数,根据需要自行修改
public final Class<?>[] PRE_ARGS_TYPE = new Class<?>[] {String.class,String.class}; //默认的参数的类型,根据需要自行修改 public int convert_if_exist(String name,String value,String field1,String field2){ //可修改成自个的业务逻辑
System.out.println("name = " + name);
System.out.println("value = " + value);
System.out.println(field1 + " " + field2);
return 0;
} public int convert_if_exist(String name,String value,String field1,String field2,String field3){//可修改成自己的业务逻辑
System.out.println("name = " + name);
System.out.println("value = " + value);
System.out.println(field1 + " " + field2 + " " + field3);
return 0;
}//要添加函数,均在这个类中添加并配置进配置文件中即可
}
package com.java.reflect; public interface IFunction { }
2、在数据库中的配置(可以改成其他方式)
可以看到数据库中配置了三条记录,仔细点会发现,其实就是1中的两个函数,只是组合了罢了。而且第一条和第二条记录也只是参数不同!!!
接下来只要通过反射,写个通用的代码,来找到并且执行这两个函数,那就万事大吉了。来看下实现:
package com.java.reflect; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import org.apache.commons.lang.StringUtils; public class Utils {
public static boolean initFunctions(IFunction obj,List<Func> dst,String funcStr){ if (StringUtils.isEmpty(funcStr) || StringUtils.isBlank(funcStr))
return true;
int PRE_ARGS_NUM = -1;
Class<?>[] PRE_ARGS_TYPE = null;
try {
PRE_ARGS_NUM = obj.getClass().getDeclaredField("PRE_ARGS_NUM").getInt(obj);
PRE_ARGS_TYPE = (Class<?>[]) obj.getClass().getDeclaredField("PRE_ARGS_TYPE").get(obj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} List<String> funcs = getFunctions(funcStr);
for (String func : funcs) {
String funcName = getFuncName(func);
String[] funcParams = getFuncParams(func); Class<?>[] paramsType = new Class[funcParams.length + PRE_ARGS_NUM];
Arrays.fill(paramsType, PRE_ARGS_NUM, paramsType.length, String.class);
System.arraycopy(PRE_ARGS_TYPE, 0, paramsType, 0, PRE_ARGS_NUM); try {
Method method = obj.getClass().getMethod(funcName, paramsType); //根据函数名 && 参数类型,找到对应的函数 dst.add(new Func(obj, method, PRE_ARGS_NUM, funcParams));
} catch (SecurityException e) {
// TODO Auto-generated catch block
//LOG.error("Error when parse method " + funcName, e);
return false;
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
//LOG.error("Error when parse method " + funcName, e);
return false;
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} return dst.size() > 0;
}
public static List<String> getFunctions(String funcStr){
List<String> ret = new ArrayList<String>(); if (StringUtils.isEmpty(funcStr) || StringUtils.isBlank(funcStr))
return ret; int preIndex = 0; // 截取函数指针
boolean in = false; // 留着扩展,取函数中的参数
for (int i = 0; i <= funcStr.length();) {
if (!in && (i == funcStr.length() || funcStr.charAt(i) == ';') && preIndex != i) {
String func = funcStr.substring(preIndex, i).trim();
if (StringUtils.isNotEmpty(func) && StringUtils.isNotBlank(func)) {
ret.add(func);
} i = i + 1;
preIndex = i;
continue;
} if (i < funcStr.length() && funcStr.charAt(i) == '\"' && (i - 1 < 0 || funcStr.charAt(i - 1) != '\\'))
in ^= true; i = i + 1;
} return ret;
}
public static String[] getFuncParams(String func) {
int idx = func.indexOf('(');
if (idx != -1) {
String params = func.substring(idx + 1, func.length() - 1);
int count = getParamsCount(params);
String[] args = new String[count];
for (int i = 0, j = 0; i < count && j < params.length();) {
boolean in = false;
for (int k = j; k <= params.length(); k++) {
if (!in && (k == params.length() || params.charAt(k) == ',')) {
args[i] = params.substring(j, k).trim();
if (args[i].startsWith("\""))
args[i] = args[i].substring(1);
if (args[i].endsWith("\""))
args[i] = args[i].substring(0, args[i].length() - 1); args[i] = args[i].replaceAll("\\\\\"", "\""); i = i + 1;
j = k + 1;
break;
} if (params.charAt(k) == '\"' && (k - 1 < 0 || params.charAt(k - 1) != '\\'))
in ^= true;
}
} return args;
}
return new String[0];
}
public static String getFuncName(String func) {
int idx = func.indexOf('(');
if (idx != -1)
return func.substring(0, idx).toLowerCase();
return null;
}
public static int getParamsCount(String params) {
if (StringUtils.isEmpty(params) || StringUtils.isBlank(params))
return 0; int cnt = 0;
boolean in = false;
for (int i = 0; i < params.length(); i++) {
if (params.charAt(i) == '\"' && (i - 1 < 0 || params.charAt(i - 1) != '\\'))
in ^= true;
if (!in && params.charAt(i) == ',')
cnt++;
} return cnt + 1;
} }
package com.java.reflect; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class Func {
private IFunction _obj;
private Method _method;
private Object[] _args; //函数需要的参数,包含两部分(1、默认的参数个数及类型;2、数据库配置中的参数个数及类型)
private int _preArgsNum; public Func(IFunction obj, Method method, int preArgsNum, String... args) {
this._obj = obj;
this._method = method;
this._preArgsNum = preArgsNum;
this._args = new Object[args.length + preArgsNum];
System.arraycopy(args, 0, this._args, preArgsNum, args.length); //保存数据库中配置的参数个数及类型
} public Object call(Object... args) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException { if (args.length != this._preArgsNum)
throw new IllegalArgumentException("Illegal number of the arguments, need " + this._preArgsNum + " but "
+ args.length + ".");
System.arraycopy(args, 0, this._args, 0, args.length); //保存默认的参数个数及类型
return this._method.invoke(this._obj, this._args); //调用并运行配置中的函数 } }
3、使用(非常简单,main调用下即可)
package com.java.reflect; import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List; public class ReflectMethod { public static void main(String[] args) {
ConvertFunction convert = new ConvertFunction();
List<Func> dst = new ArrayList<Func>();
String funcStr = "convert_if_exist("field1","field2");convert_if_exist("field1\","field2","field3");";//假设从数据库中读出出来了
Utils.initFunctions(convert, dst, funcStr);
for(int i = 0;i<dst.size();i++){
try {
dst.get(i).call("defaultKey","defaultValue");//调用,默认的两个参数此时传入,和数据库配置中的field1,field2无关,视业务而定
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4、运行结果
总结:
这样业务的变更不会有很多的.java文件产生,只会在ConvertFunction.java中不断的添加自定义的函数,并且将添加的函数配置的文件或者数据库中即可生效。而且很多成员变量都能共用!有人会质疑这样ConvertFunction.java文件会越来越大,不错,这是肯定的,各有各的好处,看大家是希望管理多个.java文件呢,还是只关注一个.java文件,n个函数。看自己的需求而定,没有那种最好,只有那种最适合自己的业务。
java中通过反射获取方法并且调用(getMethod和invoke深入)实践的更多相关文章
- java中使用反射获取pojo(实体)类的全部字段值
说起反射.不得不说它实在是太强大了,通过反射就能够轻轻松松拿到各种东东,假设你想在项目中解除对某个类的依赖,能够考虑用反射. 今天跟大家分享的是通过java中的反射,获取pojo类的全部字段值. 为什 ...
- java中使用反射获取pojo(实体)类的所有字段值
出处:https://developer.aliyun.com/article/239346 说起反射,不得不说它实在是太强大了,通过反射就可以轻轻松松拿到各种东东,如果你想在项目中解除对某个类的依赖 ...
- java 中利用反射机制获取和设置实体类的属性值
摘要: 在java编程中,我们经常不知道传入自己方法中的实体类中到底有哪些方法,或者,我们需要根据用户传入的不同的属性来给对象设置不同的属性值,那么,java自带的反射机制可以很方便的达到这种目的,同 ...
- <经验杂谈>C#中一种最简单、最基本的反射(Reflection):通过反射获取方法函数
说起反射之前和很多用C#/.net的同仁们一样,相比于一般应用层对数据的增删改查总有点觉得深奥到难以理解.其实程序这东西,用过.实践过就很简单,我一直这么认为. 先说下概念:反射 Reflection ...
- java中多线程执行时,为何调用的是start()方法而不是run()方法
Thead类中start()方法和run()方法的区别 1,start()用来启动一个线程,当调用start()方法时,系统才会开启一个线程,通过Thead类中start()方法来启动的线程处于就绪状 ...
- Java中的反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- java中的反射机制在Android开发中的用处
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...
- struts2 笔记01 登录、常用配置参数、Action访问Servlet API 和设置Action中对象的值、命名空间和乱码处理、Action中包含多个方法如何调用
Struts2登录 1. 需要注意:Struts2需要运行在JRE1.5及以上版本 2. 在web.xml配置文件中,配置StrutsPrepareAndExecuteFilter或FilterDis ...
- 浅说Java中的反射机制(二)
写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...
随机推荐
- 简单的php表单
表单的三种传递机制: $_GET:不安全,传递的参数会显示在url中. $_POST:相对安全,隐形传递. $_REQUEST:宽松的,包含所有 GET.POST.COOKIE 和 FILE 的数据. ...
- JS数据类型&&typeof&&其他
1. 5种基本数据类型: 1. String 2. Number 3. Boolean 4. Undefined 5. Null 2. 1种复杂数据类型:Object 3. 检测变量的数据类型:typ ...
- Oracle删除表、字段之前判断表、字段是否存在
这篇文章主要介绍了Oracle删除表.字段之前判断表.字段是否存在的相关资料,需要的朋友可以参考下 在Oracle中若删除一个不存在的表,如 “DROP TABLE tableName”,则会提示: ...
- Codeforces Round #208 (Div. 2)
A - Dima and Continuous Line 水题:直接模拟: #include<cstdio> #define maxn 1005 using namespace std; ...
- 玩转AWS CloudWatch微信告警
做海外业务时大多使用亚马逊 AWS 服务,配套AWS 监控 CloudWatch 功能强大,如果能和微信结合就更棒了.现在分享下如何玩转 CloudWatch 微信通知. AWS EC2 云主机配套的 ...
- Android list1去除list2中的元素
public static void main(String[] args) { List<String> firList = new ArrayList<String>(); ...
- Java按位置解析文本文件(使用Swing选择文件)
工作中遇到这样的一个需求,按位置解析一些文本文件,它们由头部.详情.尾部组成,并且每一行的长度可能不一样,每一行代表的意思也可能不一样,但是每一行各个位置代表的含义已经确定了. 例如有下面这样一段文本 ...
- Android Service 生命周期和使用注意项
一.基础知识 服务一般分为两种: 1:本地服务, Local Service 用于应用程序内部.在Service可以调用Context.startService()启动,调用Context.stopS ...
- RxJava开发精要4 – Observables过滤
原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...
- FORM Save : ORA-01403 FRM-40735 ORA-06502
症状: FORM开发后挂上服务器后,运行保存按键提示: ORA-01403: 未找到任何数据 ----------------------------------------------------- ...