在struts2的action中使用字段级参数注入

上篇我们提到了使用SetAndGet注解进行自动生成set/get方法,那么在开发模式下, 我们所使用的IDE,在进行了代码修改之后,会自动地进行重新编译代码并进行hotswap操作。这个操作会使得在启动时生成的set/get失效或者被删除。解决这个问题的一个方法,就是使用字段级参数注入,即我们在开发模式下不需要生成set/get,而是直接使用相应的字段进行操作。

在当前的struts2版本中,默认是不支持字段设置值的,但是ognl本身是支持的。在ognl中,提供了以下2个方法来完成字段的获取和设置。

OgnlRuntime.setFieldValue(ognlContext, o, name.toString(), value);//设置字段的值
OgnlRuntime.getFieldValue(ognlContext, o, name.toString());//获取字段的值

那么,我们可以通过相应的处理。让在开发模式下,在使用常规参数处理之后,再启用字段级参数处理就达到相应的目的了。在整个处理中,我们需要保证以下2点就可以达到目的了。

  1. 在action进行参数注入时,可以支持字段级的注入,涉及的访问器为CompoundRootAccessor
  2. 在相应的字段为null时,我们可以按照常规的处理自动创建相应的值,以便进行注入,涉及的处理器为InstantiatingNullHandler

1    字段参数注入

原生的CompoundRootAccessor类中没有处理字段的参数设置,那么我们需要扩展相应的功能。需要处理的方法包括获取值和设置值,那么即要override方法setProperty和getProperty

在方法setProperty中,我们只需要保证在没有找到属性值,加入我们的字段处理即可。代码如下:

//处理Property
 else if(OgnlRuntime.hasField(ognlContext, o, o.getClass(), name.toString())) {
					OgnlRuntime.setFieldValue(ognlContext, o, name.toString(), value);
					return;
}
//处理map类型

在方法getProperty中,与set类似,在相应的逻辑中加入字段处理。

else if(OgnlRuntime.hasField(ognlContext, o, o.getClass(), name.toString())) {
	try {
		return OgnlRuntime.getFieldValue(ognlContext, o, name.toString());
	} catch(NoSuchFieldException e) {
		logger.warn("没有字段'" + name.toString() + "'的值", e);
	}
}

2    创建NULL值

原生的InstantiatingNullHandler并没有针对字段进行处理,那么我们也只需要继承并override相应的逻辑即可。如下所示:

PropertyDescriptor pd = reflectionProvider.getPropertyDescriptor(realTarget.getClass(), propName);
clazz = pd == null ? null : pd.getPropertyType();
if(clazz == null) {
       Field field = reflectionProvider.getField(realTarget.getClass(), propName);
	if(field != null)
		clazz = field.getType();
}

其中的reflectionProvider.getField即是新增加的代码。

3    启用新增加的处理器

我们新增加的这2个类均是直接扩展(修改)原有的struts内部类,而这些类的定义是放在sturts-default.xml中的。在不修改相应jar包的情况下,如何放入我们的类呢。其实不难,我们只需要将我们的类追加进原有struts2的containerBuilder即可。containerBuilder是用于启动struts2时创建容器的构造器,我们可以实现接口ConfigurationProvider以提供特定的扩展。那么,这样就很好处理了,只需要实现之,并加入相应代码即可。如下所示:

			builder.setAllowDuplicates(true);//这一行必须调用,即允许重复定义。在此模式下,后面的定义将覆盖之前的定义
			builder.factory(ognl.MethodAccessor.class, "com.opensymphony.xwork2.util.CompoundRoot",
					CompoundRootAccessor.class);//我们自实现的字段注入类
			builder.factory(ognl.PropertyAccessor.class, "com.opensymphony.xwork2.util.CompoundRoot",
					CompoundRootAccessor.class);//我们自实现的字段注入类
			builder.factory(com.opensymphony.xwork2.conversion.NullHandler.class, "java.lang.Object",
					InstantiatingNullHandler.class);//我们自实现的null处理类

总结
经过这样的处理,struts2就能使用字段级注入了。但直接访问字段在安全或效率上或多或少存在一些问题。即我不推荐在生产模式中启用这种处理方式。具体如何切换,可以参考前一篇文章。我们可以在开发模式中,打开这种处理;而在生产模式下关注这种处理即可,在保证代码整洁的情况下,代码一点也无需修改。

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201312250001.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

电子邮件地址不会被公开。 必填项已用*标注