How does read properties from property-placeholder with annotations in spring 2.5.
对spring那堆破烂配置文件早就烦不胜烦, 要依着我的意思不考虑其他人的感受早就换了。
spring2.5开始引入了对annotation方式配置bean的支持,这种模式可以简化配置工作,但是并未提供常用的placeholder的支持,这里给出一个比较简单的解决方法。
研究发现,确实可以部分的取代xml文件,使用placeholder设置基本类型的操作可以最常用的功能, 就是不知道为何天才的21Interfacer们居然忘记了加入对placeholder的支持。
琢磨了一下, 有2种办法可以解决这个问题
1. 最简单的办法, 在 context.xml 文件中配置对应属性的 类型对象
<bean id="form.store.dir" class="java.lang.String">
<constructor-arg type="java.lang.String" value="${form.store.dir}" />
</bean>
这样在scan的时候会自动把这些内容注入到bean中去, 好吧, 这不大傻么,写的xml文件比以前还多,而且这次更好,要多改2个地方。
2. 扩展
其一、 增加一个自定义的annotation, 然后增加对容器中bean创建过程的拦截, 判断属性,强行设置。缺点是,嗯,又要多写东西,而且这个anno 跟自己整xml有啥区别。
其二、 对placeholdconfiguration进行修改, 把所有的palcehold的对应的property对象都创建一个bean,注册到容器中去缺点是不能非常好的识别对象的类型, 主要是整数,浮点数和手机号码一类,现在约定只处理整数,超过10位按字符串处理
选择了第二个方式实现,这样可以不破坏基本结构,未来21Interface的牛人们想起来可怜一些我们的时候升级包不用改代码。
参考实现如下
<bean class="joycode.oame.util.spring.AnnotationPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
public class AnnotationPropertyPlaceholderConfigurer extends
PropertyPlaceholderConfigurer {
protected final Log logger = LogFactory.getLog(AnnotationPropertyPlaceholderConfigurer.class);
protected void processProperties(
ConfigurableListableBeanFactory beanFactoryToProcess,
Properties props) throws BeansException {
super.processProperties(beanFactoryToProcess, props);
System.out.println(beanFactoryToProcess.getClass());
if (beanFactoryToProcess instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactoryToProcess;
Enumeration<Object> keys = props.keys();
while(keys.hasMoreElements()) {
String key = (String) keys.nextElement();
String value = props.getProperty(key);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setAbstract(false);
rbd.setLazyInit(true);
rbd.setAutowireCandidate(true);
ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
rbd.setConstructorArgumentValues(constructorArgumentValues);
logger.debug("register placehold key " + key + " " + value);
if (StringUtils.isNotBlank(value) && value.length() < 11 && StringUtils.isNumeric(value)) {
Integer intValue = Integer.parseInt(value);
constructorArgumentValues.addIndexedArgumentValue(0,
intValue);
rbd.setBeanClass(Integer.class);
} else if (value.toLowerCase().equals("false") || value.toLowerCase().equals("true") ) {
Boolean boolValue = Boolean.parseBoolean(value);
constructorArgumentValues.addIndexedArgumentValue(0,
boolValue);
rbd.setBeanClass(Boolean.class);
} else {
constructorArgumentValues.addIndexedArgumentValue(0,
value);
rbd.setBeanClass(String.class);
}
registry.registerBeanDefinition(key, rbd);
}
}
}
}
这样子bean用起来就有点样子了,嗯省了2个配置文件,重构时也不用到处改了。
@Service
public class GetAllTableFormAction extends AbstractAction {
@Autowired
@Qualifier("form.store.dir")
private String fileDir = null;
此处需要注意,因为是把placehold包装成一个bean, 对于基本类型, spring当前还不支持自动unbox。所以需要使用对象类型来申明属性,比如
@Autowired
@Qualifier("socket.server.port")
private Integer port = 4000; //使用wraper类型来代替基本类型
还需要在context中加入对自动注入的bean的搜索路径
<context:component-scan base-package="joycode.oame.service.action, xxxx.com.cc" />
[然后发现包搜索居然不支持2个以上的包,真是大傻呀],重新测试了一下,其实多个包用","分割是可以的,我测试又马大哈了。
折腾一上午的感觉是,这玩意主要还是配合xml使用的,目前还不可能完全取代xml(以后应该也不可能,xml在某些方面还是有优势的,比如aop的配置),命真苦。
nnd,说是为了简化j2ee抛出一个spring,结果现在这玩意的复杂度。。。