How does read properties from property-placeholder with annotations in spring 2.5.
對(duì)spring那堆破爛配置文件早就煩不勝煩, 要依著我的意思不考慮其他人的感受早就換了。
spring2.5開始引入了對(duì)annotation方式配置bean的支持,這種模式可以簡(jiǎn)化配置工作,但是并未提供常用的placeholder的支持,這里給出一個(gè)比較簡(jiǎn)單的解決方法。
研究發(fā)現(xiàn),確實(shí)可以部分的取代xml文件,使用placeholder設(shè)置基本類型的操作可以最常用的功能, 就是不知道為何天才的21Interfacer們居然忘記了加入對(duì)placeholder的支持。
琢磨了一下, 有2種辦法可以解決這個(gè)問題
1. 最簡(jiǎn)單的辦法, 在 context.xml 文件中配置對(duì)應(yīng)屬性的 類型對(duì)象
<bean id="form.store.dir" class="java.lang.String">
<constructor-arg type="java.lang.String" value="${form.store.dir}" />
</bean>
這樣在scan的時(shí)候會(huì)自動(dòng)把這些內(nèi)容注入到bean中去, 好吧, 這不大傻么,寫的xml文件比以前還多,而且這次更好,要多改2個(gè)地方。
2. 擴(kuò)展
其一、 增加一個(gè)自定義的annotation, 然后增加對(duì)容器中bean創(chuàng)建過程的攔截, 判斷屬性,強(qiáng)行設(shè)置。缺點(diǎn)是,嗯,又要多寫東西,而且這個(gè)anno 跟自己整xml有啥區(qū)別。
其二、 對(duì)placeholdconfiguration進(jìn)行修改, 把所有的palcehold的對(duì)應(yīng)的property對(duì)象都創(chuàng)建一個(gè)bean,注冊(cè)到容器中去缺點(diǎn)是不能非常好的識(shí)別對(duì)象的類型, 主要是整數(shù),浮點(diǎn)數(shù)和手機(jī)號(hào)碼一類,現(xiàn)在約定只處理整數(shù),超過10位按字符串處理
選擇了第二個(gè)方式實(shí)現(xiàn),這樣可以不破壞基本結(jié)構(gòu),未來21Interface的牛人們想起來可憐一些我們的時(shí)候升級(jí)包不用改代碼。
參考實(shí)現(xiàn)如下
<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用起來就有點(diǎn)樣子了,嗯省了2個(gè)配置文件,重構(gòu)時(shí)也不用到處改了。
@Service

public class GetAllTableFormAction extends AbstractAction
{
@Autowired
@Qualifier("form.store.dir")
private String fileDir = null;

此處需要注意,因?yàn)槭前裵lacehold包裝成一個(gè)bean, 對(duì)于基本類型, spring當(dāng)前還不支持自動(dòng)unbox。所以需要使用對(duì)象類型來申明屬性,比如
@Autowired
@Qualifier("socket.server.port")
private Integer port = 4000; //使用wraper類型來代替基本類型

還需要在context中加入對(duì)自動(dòng)注入的bean的搜索路徑
<context:component-scan base-package="joycode.oame.service.action, xxxx.com.cc" />


[然后發(fā)現(xiàn)包搜索居然不支持2個(gè)以上的包,真是大傻呀],重新測(cè)試了一下,其實(shí)多個(gè)包用","分割是可以的,我測(cè)試又馬大哈了。
折騰一上午的感覺是,這玩意主要還是配合xml使用的,目前還不可能完全取代xml(以后應(yīng)該也不可能,xml在某些方面還是有優(yōu)勢(shì)的,比如aop的配置),命真苦。
nnd,說是為了簡(jiǎn)化j2ee拋出一個(gè)spring,結(jié)果現(xiàn)在這玩意的復(fù)雜度。。。
<context:component-scan base-package="com.test.service,com.test.dao"/>
謝謝,改了,原來測(cè)試有誤