(JAVASE)CSFrameWork详解(Request处理、action、反射机制)

这篇博客探讨了在Java应用中如何使用反射机制结合XML配置文件来处理动态调用未知方法的场景。解析XML文件以获取action及其对应的方法、参数信息,然后通过反射创建对象并调用相应的方法。在处理请求时,根据接收到的参数字符串反序列化为参数对象,正确匹配方法签名并执行。内容涉及Java反射、XML解析和泛型擦除机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在app层,会有许多由开发者书写的新方法,这些方法是无法从底层预支的,但是在底层代码书写请求、回复等操作时,应该对应不同action,调用其处理方法。
相当于对action的处理,基于反射机制调用未来配置的方法。
而这些方法的获取此次通过解析xml实现,如:

<actions>
	<action name="login" class="StudentAction" method="login">
		<parameter name="id" type="string"></parameter>
		<parameter name="password" type="string"></parameter>
	</action>
	
	<action name="registry" class="StudentAction" method="registry">
		<parameter name="id" type="string"></parameter>
		<parameter name="nick" type="string"></parameter>
		<parameter name="password" type="string"></parameter>
	</action>
</actions>

xml需包括所有新添加的方法,标注action名称及其对应的类,方法名称,各个参数的名称及数据类型。(尤其参数,因为java的方法重载性,需要精准参数才能取出对应方法)

那么首先的问题是从xml中提取出所有action对应方法并存到action池中,避免之后每次调用都要现解析xml寻找方法。
解析XML文件并生成action池:

public static void scanActionMapping(String xmlPath) 
			throws XMLNotFoundException, SAXException, IOException, Throwable {
		new XMLParser() {
			@Override
			public void dealElement(Element element, int index) throws Throwable {
				String action = element.getAttribute("name");
				String className = element.getAttribute("class");
				Class<?> klass = Class.forName(className);
				@SuppressWarnings("deprecation")
				Object object = klass.newInstance();
				String methodName = element.getAttribute("method");
				
				ActionBeanDefinition abd = new ActionBeanDefinition();
				abd.setKlass(klass);
				abd.setObject(object);
				
				new XMLParser() {
					@Override
					public void dealElement(Element element, int index) throws Throwable {
						String parameterName = element.getAttribute("name");
						String strParameterType = element.getAttribute("type");
						
						ParameterDefinition pd = new ParameterDefinition();
						pd.setName(parameterName);
						pd.setType(TypeParser.toType(strParameterType));
						
						abd.addParameter(pd);
					}
				}.parseTag(element, "parameter");
				
				Class<?>[] parameterTypes = new Class<?>[abd.getParameterCount()];
				int i = 0;
				while (abd.hasNext()) {
					ParameterDefinition pd = abd.nextParameter();
					parameterTypes[i++] = pd.getType();
				}
				Method method = klass.getDeclaredMethod(methodName, parameterTypes);
				abd.setMethod(method);
				
				actionPool.put(action, abd);
			}
		}.parseTag(XMLParser.newDocument(xmlPath), "action");
	}

首先按action词条解析,获取action的名称;获取其对应的类的名称,由类的名称反射出该类,再将该类实例化;获取方法名称(因为重载机制,没有参数无法获取去具体方法)。

初始化一个ABD(一个ABD保存一个类、对象、方法),将该类与对象加入一个ABD。

接着该解析parameter参数词条了:
首先提取出参数名称,类型(转换:int->Integer),并都加入一个PD(一个PD代表一个)参数,再将该PD加入ABD的参数列表。
依据ABD参数列表数量新建一个类数组存放参数数据类型,按ABD参数列表的顺序将参数数据类型加入到该类数组。
按方法名称、参数数据类型由类获取对应方法,将方法加入到ABD中,最终将该ABD(存储着类、对象、方法)加入到action池中,以便后续调用。

在说明具体用法之前,先说明一下java的泛型擦除机制:类似List<泛型>,当我们想要获取具体泛型表示的类型时,利用getClass只是返回List类型,因此在需要精确获取参数数据类型的情形下,明显无法完成该需求。
Gson提供了一个方法:private static Type mapType = new TypeToken<Map<String, String>>() {}.getType();
上述方法得到的mapType为Map<java.lang.String, java.lang.String>,这样就能获取MAP及其内部所存数据的数据类型。

而在请求传来时,所发送的参数是Gson字符串,要想获取其包含的数据类型及数据值,需要将Gson字符串反解析出来。AM:

this.argMap = gson.fromJson(parameterString, mapType);

该图存储着参数名及一个Json字符串(包含参数值及参数数据类型)的键值对。
具体对Request做出处理:

public Object dealRequest(String action, String parameter) throws Exception {
		// 根据action获取对应的ActionBeanDefinition对象;
		ActionBeanDefinition abd = ActionBeanFactory.getActionBean(action);
		// 获取action对应的方法
		Method method = abd.getMethod();
		// 获取action对应的方法在反射执行时,所需的对象;
		Object object = abd.getObject();
		
		// 根据字符串化的参数,反向构建Map<String, String>
		// 这个Map的键是参数名称,值是参数对象值的gson字符串
		// 但是,Map的无序性,使得不能保证参数顺序正常;
		ArgumentMaker argument = new ArgumentMaker(parameter);
		// ActionBeanDefinition中的getParameterCount()能得到参数个数
		Object[] parameterValues = new Object[abd.getParameterCount()];
		int index = 0;
		// 根据method得到这个方法的所有参数Parameter;用的是反射机制手段
		Parameter[] parameters = method.getParameters();
		// 按照ActionBeanDefinition中的参数列表中参数的顺序访问参数:
		while (abd.hasNext()) {
			// 获取参数信息
			ParameterDefinition pd = abd.nextParameter();
			// 获取参数名称
			String parameterName = pd.getName();
			// 按照顺序获取参数Type,这是能保证范型对象正常处理的关键!
			Type parameterType = parameters[index].getParameterizedType();
			// 得到对应参数名称的参数值,并保证范型得到处理
			parameterValues[index] = argument.getParameter(parameterName, parameterType);
			index++;
		}
		
		Object result = null;
		result = method.invoke(object, parameterValues);
		
		return result;
	}

首先根据传来的action参数,在之前生成的action池中找到该action对应的ABD,取出其方法、对象。
用反射机制得到方法的全部参数Parameter并生成一个数组。
我们现在得到了一个参数数据类型数组,ABD中有一个参数列表,其元素是PD,取出PD后可得到参数名称,在Parameter数组中可以获取参数的数据类型,当获取到参数名称及参数数据类型之后,就可以通过:

public Object getParameter(String name, Type type) {
		String strValue = this.argMap.get(name);
		return gson.fromJson(strValue, type);
	}
parameterValues[index] = argument.getParameter(parameterName, parameterType);

获取该参数值并加入数组。
当获取完全部参数数值,我们就可以通过方法的反射机制

Object result = method.invoke(object, parameterValues);

即调用了对应方法。

反射:

Class<?> klass = Class.forName(String className);
Object object = klass.getDeclaredConstructor().newInstance();
Method method = klass.getDeclaredMethod(String methodName, Class<?> parameterTypes);
Field[] fileds = klass.getDeclaredFields();
result = method.invoke(object, parameterValues);

作用:
1.按照类名称获取类
2.实例化该类获得对象
3.按照方法名称及参数数据类型获取方法
4.获取该类的成员
5.用对象及方法所需的数据值调用方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值