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,结果现在这玩意的复杂度。。。