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,結果現在這玩意的復雜度。。。