利用Java註解特性載入屬性檔案(properties)的值到Java類

來源:互聯網
上載者:User

在此之前我都是寫個PropertyUtil類來載入設定檔,然後通過get方法,把key對應的值取出來.

Spring提供一個PropertyPlaceholderConfigurer類,可以讀取設定檔,然後在Spring設定檔通過${hibernate.dialect}這種方式注入到JavaBean中,有個不好的地方就是,要在代碼中取的時候不是很方便.

然後在接觸到Java註解特註解技術以後,感覺這個東東很好,hibernate映射,WebService都可以通過註解來完成,方便的很多,然後就在想能不能通過Java註解特性載入屬性檔案(properties)的值到Java類裡面呢?

其實上面一篇寫在Spring中JavaBean的初始化順序就是為現在寫這個做準備的,要實現現在說的這個功能,大體方案有如下:

1.定義一個註解類

2.在需要載入屬性的JavaBean的屬性set方法上寫註解,註解的參數就是key

3.在Spring啟動的時候,去讀取屬性檔案,然後把值賦給JavaBean

我們在上一篇寫在Spring中JavaBean的初始化順序提到了,如果一個JavaBean實現了BeanPostProcessor介面,那麼其他Bean初始化以後都會交給這個Bean來處理.這樣我們就可以寫一個JavaBean實現BeanPostProcessor介面,這個Bean有個屬性,它指向屬性檔案路徑,在這個Bean初始化的時候讀取屬性檔案內容,然後在postProcessBeforeInitialization方法裡面對寫了註解的Bean進行賦值.這樣一個實現思路似乎很順其自然,都是自己覺得不是很好,Spring通過PropertyPlaceholderConfigurer這樣類來載入屬性檔案,而我們有寫了另外一個類,這樣一是不夠統一,二是不夠可能會造成多個屬性檔案.解決辦法就是擴充PropertyPlaceholderConfigurer類.寫一個類繼承PropertyPlaceholderConfigurer類.然後在PropertyPlaceholderConfigurer初始化完成以後,擷取載入的屬性檔案內容,在postProcessBeforeInitialization裡面把寫過註解的類屬性進行賦值.那麼怎麼確定什麼時候PropertyPlaceholderConfigurer載入完成呢,根據Spring中JavaBean的初始化順序,我們知道一個JavaBean如果實現了InitializingBean介面,那麼Spring容器會在這個Bean初始化以後調用afterPropertiesSet方法,現在我寫個類繼承PropertyPlaceholderConfigurer類,實現BeanPostProcessor, InitializingBean 這個兩個介面那麼剛剛提到的問題就可以解決了,下面是實現代碼

package com.test.annotation;
import java.lang.reflect.Method;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.util.ReflectionUtils;
public class AnnotationBeanPostProcessor extends PropertyPlaceholderConfigurer implements BeanPostProcessor, InitializingBean {
   private java.util.Properties pros;
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName)
       throws BeansException {
     // TODO Auto-generated method stub
     return bean;
   }
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName)
       throws BeansException {
     if(bean.getClass().getAnnotation(Property.class)!=null){
       Method[] methods = bean.getClass().getDeclaredMethods();
       for (Method method : methods) {  
         Property p = method.getAnnotation(Property.class);
         if(p!=null){
//         這裡進行參數類型轉換
           Object para=pros.getProperty(p.name());
           if((method.getParameterTypes()[0]).getName().equals("java.lang.Integer")){
             para= new Integer(para.toString());
           }
           ReflectionUtils.invokeMethod(method, bean, new Object[]{para});
         }
       }
     }
     return bean;
   }
   @Override
   public void afterPropertiesSet() throws Exception {
     pros = mergeProperties();
   }
}
package com.test.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Property {
   String name() default "";
}
package com.test;
import com.test.annotation.Property;
@Property
public class Bean {
   private String name;
   private Integer age;
private String address;
   public String getName() {
     return name;
   }
   public void setName(String name) {
     this.name = name;
   }
   public String getAddress() {
     return address;
   }
   @Property(name="com.test.Bean.address")
   public void setAddress(String address) {
     this.address = address;
   }
   public Integer getAge() {
     return age;
   }
   @Property(name="com.test.Bean.age")
   public void setAge(Integer age) {
     this.age = age;
   }
}
package com.test;
import com.test.annotation.Property;
@Property
public class JavaBean {
   private String name;
   private String address;
   public String getName() {
     return name;
   }
   @Property(name="com.test.JavaBean.name")
   public void setName(String name) {
     this.name = name;
   }
   public String getAddress() {
     return address;
   }
   public void setAddress(String address) {
     this.address = address;
   }
}
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
   /**
   * @param args
   */
   public static void main(String[] args) {
     ApplicationContext context = 
         new ClassPathXmlApplicationContext("spring.xml");
     System.out.println("載入設定檔結束");
     System.out.println("--------------------------------------------");
     JavaBean javaBean=(JavaBean)context.getBean("javaBean");
     System.out.println(javaBean.getName());
     System.out.println(javaBean.getAddress());
     System.out.println("--------------------------------------------");
     Bean bean=(Bean)context.getBean("bean");
     System.out.println(bean.getName());
     System.out.println(bean.getAddress());
     System.out.println(bean.getAge());
     System.out.println("--------------------------------------------");
   }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   <bean id=
attribute-value>"propertyConfigurer" class="com.test.annotation.AnnotationBeanPostProcessor">
     <property name="locations">
       <list>
         <value>classpath*:system.properties</value>
       </list>
     </property>
   </bean>
   <bean id="javaBean" class="com.test.JavaBean">
     <property name="address" value="${com.test.JavaBean.address}"></property>
   </bean>
   <bean id="bean" class="com.test.Bean">
     <property name="name" value="${com.test.Bean.name}"></property>
   </bean>
</beans>

ps:之所以要繼承PropertyPlaceholderConfigurer類,還有一個原因就是,原來通過${}注入值的方式還可以用

BeanPostProcessor有兩個方法,為什麼要寫在postProcessBeforeInitialization裡面,而不是postProcessAfterInitialization裡面,原因在於postProcessBeforeInitialization方法是在Bean的init方法之前執行,在init方法裡面可能會用到類的屬性,所以必須在init方法執行之前先賦值好.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.