在編寫程序的時候,總是不可避免的需要使用一些常量,甚至很多的常量.我們可以對常量進行一個很簡單的分類:
記憶性常量:主要出於程序結構上的考慮而設定的常量.譬如為了避免一個沒有字面意思的魔法數,或者避免拼寫容易出錯,或者不容記住的內容.
業務性常量:表示一個業務上的一個特定業務實體的屬性或屬性值.
很多的時候,一個業務性常量很多時候也是一個記憶性常量.
在一個大型項目中,參與的人員和代碼數量通常都會比較多,沒有好的管理策略,常量的使用往往想入混亂中.譬如重複定義,其維護的值甚至還不一致,以外覆蓋;譬如僅僅為了使用某個常量,而引入某個包或者類,由此可能引出模塊間的循環依賴等.
良好的設計結構,以及嚴格的開發紀律基本上可以解決上述問題.除了有時的確是不可避免的出現以上問題外,有時一些所謂的業務常量只有在部署期間或同別的系統集成是才能獲得.所以有必要進一步的探討常量的管理手段.
記得在JavaEye上看到一篇關於Spring屬性注入的文章,靈機一動,不是恰好可以用來處理這個問題嗎?所謂屬性注入,意思是指將配置信息寫在Properties文件中,通過IOC容器透明的注入.
這麼設想下,如果常量最終都可以用配置文件配置,那麼就可以解決「業務常量只有在部署期間或同別的系統集成是才能獲得」的問題,如果同時還可以透明的宣稱使用常量,那麼幾乎所有的問題就完美了:
不害怕重複定義錯誤
消除有常量引用引起的循環引用
提供從部署期覆蓋編譯期的靈活性
使用Spring的擴展名稱空間和Java5的Annotation語法,我們可以整理出以以下思路
定義一個Annotation類
實現一個Annotation的Processor
配置Processor Bean
實現過程大致如下:
一、Annotation
@Target({ElementType.FIELD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Properties {
String name() default "";
String value() default "";
String namePrefix() default "";
String namePostfix() default "";
}
二、Processor
public class AnnotationPropertiesBeanPostProcessor extends PropertyPlaceholderConfigurer implements BeanPostProcessor, InitializingBean {
private java.util.Properties pros;
private String namePrefix = "";
private String namePostfix = "";
public void setEnabledClassList(Class[] enabledClassList) {
this.enabledClassList = enabledClassList;
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
HandlePropertiesAnnotatedBean(bean, bean.getClass());
return bean;
}
private void HandlePropertiesAnnotatedBean(Object bean, Class asClass) throws SecurityException {
if( isHandleInheritance(asClass.getSuperclass()) ){
HandlePropertiesAnnotatedBean(bean, asClass.getSuperclass());
}
Field[] fields = asClass.getDeclaredFields();
for (Field field : fields) {
if (support(field.getType())) {
handleField(bean, field, defaultIsRequired(bean, asClass));
}
}
}
private void handleField(Object bean, Field field, boolean defaultIsRequired) {
if (isProhibited(field)) {
return;
}
if (defaultIsRequired || isRequired(field)) {
try {
ReflectionUtils.makeAccessible(field);
field.set(bean, getPropertyValue(field));
} catch (Exception ex) {
Logger.getLogger(AnnotationPropertiesBeanPostProcessor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
......
三、配置 bean
Xml代碼
<bean class="com.joyplus.ext.spring.AnnotationPropertiesBeanPostProcessor" />
四、使用實例
@Properties(namePrefix="ddd")
public class Config {
@Properties(name="author")
private String author;
private String tvalue;
@Properties(value="default name",namePrefix="ooo")
private String tname;
private String nonValue;
// getter and setter
}
五、示例Properties文件內容
Xml代碼
dddauthor=用的是 class 級別的 prefix
oootname=用的是 field 級別的 prefix
dddnonValue=用sd
[火星人 ] 一種基於Spring的java程序常量管理思路已經有603次圍觀