今天实现一个ACL的通用Service,用于验权使用。实现是基于spring并自定义authz标签,但在parse params的时候遇到了难题。
说到这个相信大多数人都不陌生,这不正是spring的拓展机制之一么,用于自定义属性解析器,用最普遍的Date解析来简单回顾下它的用法:
1、自定义PropertyEditor实现
import java.beans.PropertyEditorSupport; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class UtilDatePropertyEditor extends PropertyEditorSupport { private String format = "yyyy-MM-dd"; //定义固定字符串格式 //重写父类方法 public void setAsText(String text) throws IllegalArgumentException{ SimpleDateFormat sdf = new SimpleDateFormat(format); try { Date date = sdf.parse(text); //获取时间信息 this.setValue(date); } catch(ParseException) { e.printStackTrace(); } } public void setFormat(String format) { this.format = format; } }
2、修改Spring配置文件
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.util.Date"> <bean class=".../UtilDatePropertyEditor"> <!--设置时间格式--> <property name="format" value="yyyy-MM-dd"> </bean> </entry> </map> </property> </bean> <!--创建对象attributeEditor--> <bean id="attributeEditor" class=".../AttributeEditor"> <property name="dateValue"> <value>2009-12-01</value> </property> </bean>
看上去是那么理所当然,正当我要开始编写XML配置文件的时候,发现问题不对了,这个Authz是一个通用的服务,应该作为二方库被业务方所依赖。
倘若作为应用方使用cutomEditor完全没有问题,但是作为基础提供方便不能如此设计,你该不是要使用方都import你的那份spring配置吧~下面我开始思考解决方案:
1、【可读性差】既然是自定义的Spring标签和service,那么不要搞复杂的pojo,字段都用基本类型不就没有那么多烦恼了
2、获得BeanFactory的引用,手动注册CustomEditor,先不谈取不到BeanFactory的引用,GetBean之前在哪一步植入代码,会不会感觉挺奇怪的
3、难道就没有一个与容器无关的静态方法可以调用么?
首先看下Spring PropertyEditor的实现:
[BeanWrapperImpl.convertForProperty]
if (editor == null && requiredType != null) { // No custom editor -> check BeanWrapperImpl's default editors. editor = (PropertyEditor) this.propertyEditorRegistry.getDefaultEditor(requiredType); if (editor == null && !String.class.equals(requiredType)) { // No BeanWrapper default editor -> check standard JavaBean editor. editor = BeanUtils.findEditorByConvention(requiredType); if (editor == null && !unknownEditorTypes.containsKey(requiredType)) { // Deprecated global PropertyEditorManager fallback... editor = PropertyEditorManager.findEditor(requiredType); if (editor == null) { // Regular case as of Spring 2.5 unknownEditorTypes.put(requiredType, Boolean.TRUE); } else { logger.warn("PropertyEditor [" + editor.getClass().getName() + "] found through deprecated global PropertyEditorManager fallback - " + "consider using a more isolated form of registration, e.g. on the BeanWrapper/BeanFactory!"); } } } }
使用的JDK的PropertyEditorManager来拓展Editor的管理,并且与容器无关,那么接下来的问题就很容易解决了:
1、调用PropertyEditorManager的注册方法注册解析器
2、xxxEditor与xxx位于同一个包内,也可以实现自动发现;或者调用PropertyEditorManager.setEditorSearchPath设置path
阅读开源的代码可以汲取到大家的智慧,有些功能点或许自己根本就没有考虑到,为了可以看得更远,我们应该站在巨人的肩膀上。
写这篇文章仅仅是提醒自己在开发设计的过程中一方面要为自己代码的通用性和质量负责,另一方面也要考虑这个拓展点是否足矣满足使用方的应用场景来负反馈通用性的设计。