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