Spring结合JSF使用时的组件命名支持
之前和打倒小日本做项目的时候,用seam,曾经定过一条规则,Service/Manager/DAO这个层面上由于组件数量不是特别多,所以组件命名不需要空间前缀,但是对于action层面的组件,由于可能很多,所以按功能模块划分命名空间,例如:
@Compoenent("treasure.selector"),@Component("store.main")等等,在Seam的支持下,在页面上写表达式语言的时候,没有任何问题,例如#{store.main.entity.name}
后来在某环境下,不用seam,用Spring了,发现如下的代码会有问题:
@Component("auth.main")//Spring的Annotation
public class MainAction{........}
在页面上用#{auth.main.xx}这样的表达式的时候,会出现找不到对象的错误。跟代码发现Spring提供的SpringBeanFacesELResolver里面解析的时候,先解析"auth",找不到,于是后面就解析不下去了。
问题的关键点在于这个EL解析器。Seam的ELResolver能够正确解析带命名空间的组件,而Spring的这个不行。
于是,扩展之。
首先第一步是要让系统知道有哪些命名空间,这里用了Spring的一个接口,叫做BeanFactoryPostProcesser,看名字应该能看的出来,和我们常用的BeanPostProcess道理一样,只不过实现了BeanFactoryPostProcesser接口的组件会在整个beanFactory初始化之前和之后调用。
看代码:
@Componentpublic class BeanNamespacePostProcesser implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String[] beanNames = beanFactory.getBeanDefinitionNames();for(String beanName : beanNames){if(beanName.indexOf('.') == -1)continue;else{String[] terms = beanName.split("\\.");Namespace space = Namespace.rootNamespace;for(int i = 0;i<terms.length - 1; i++){space = space.getOrCreateChild(terms[i]);}}}}}public class JSFELResolver extends SpringBeanFacesELResolver {@Overridepublic Object getValue(ELContext elContext, Object base, Object property) throws ELException { if (base == null) { return resolveBase(elContext, property); } else if (base instanceof Namespace) { return resolveInNamespace(elContext, (Namespace) base, property); }else { return null; }}private Object resolveInNamespace(ELContext elContext, Namespace base,Object property) {Object result = base.get((String) property);elContext.setPropertyResolved(true); return result;}private Object resolveBase(ELContext elContext, Object property) {if(this.getWebApplicationContext(elContext).containsBean(property.toString())){elContext.setPropertyResolved(true);return this.getWebApplicationContext(elContext).getBean(property.toString());}else{Object result = Namespace.rootNamespace.get(property.toString());if(result != null)elContext.setPropertyResolved(true);return result;}}}<el-resolver>el.JSFELResolver</el-resolver>