ALL is Well!

          敏捷是一條很長的路,摸索著前進著

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks
          這里是想介紹一下如何通過Java的注解機制,實現對bean資源的注入。主要介紹實現的方法,至于例子的實用性不必討論。
          需求:一個應用有兩個數據庫,分別為DB-A,DB-B。
          假設持久層框架使用iBatis來實現,那么SqlMapClient對象在創建時,對于兩個不同的DB連接要有兩個不同的SqlMapClient對象,
          假設我們有一個Service類為MyService.java,該類中有兩個SqlMapClient對象sqlMapA、sqlMapB分別對應著DB-A、DB-B。

          先看看我們的SqlMapClient.java類:(自定義SqlMapClient類,用來演示。)
          import java.util.Map;

          import org.apache.commons.lang.builder.ToStringBuilder;
          import org.apache.commons.lang.builder.ToStringStyle;

          @SuppressWarnings(
          "unchecked")
          public class SqlMapClient {
              
          public SqlMapClient(String s, String t) {
                  sqlMap 
          = s;
                  type 
          = t;
              }

              
              
          public SqlMapClient() {
              }


              
          private String type   = null;

              
          private String sqlMap = null;
              
          // get、set方法 略

              
          // 用于演示查詢后返回一個String的返回結果
              public String selectForObject(String sql, Map in) {
                  
          return this.toString();
              }

              
              @Override
              
          public String toString() {
                  
          return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("sqlMap", sqlMap)
                  .append(
          "type", type).toString();
              }

          }

          MyService.java類實現:
          import java.util.Map;

          @SuppressWarnings(
          "unchecked")
          public class MyService {
              @DataSource(type
          ="B", sqlMap="com/annotation/sql-map-config-B.xml")
              
          private SqlMapClient sqlMapB = null;
              
              @DataSource(type
          ="A", sqlMap="com/annotation/sql-map-config-A.xml")
              
          private SqlMapClient sqlMapA = null;
              
              
          // get、set方法 略

              
          // 模擬在DB-B數據庫取得數據
              public String selectForObjectFromB(String sql, Map in) {
                  
          return sqlMapB.selectForObject(""null);
              }

              
              
          // 模擬在DB-A數據庫取得數據
              public String selectForObjectFromA(String sql, Map in) {
                  
          return sqlMapA.selectForObject(""null);
              }

          }

          接下來就是我們的注解類:DataSource.java
          import java.lang.annotation.ElementType;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;

          @Target(ElementType.FIELD)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface DataSource {
              
          /**
               * Dao的類型
               * 
          @return
               
          */

              String type() 
          default "A"// 連接的數據庫類型 A or B
              
              String sqlMap() 
          default ""// Sql-Map-Config文件的路徑,用于加載iBatis的SqlMapClient對象
          }

          定義資源注入的接口 IFieldWiring.java。
          之所以這里要定義這個接口,是為了以后擴展用,我們很方便的定義更多的自定義注解。
          IFieldWiring.java

          import java.lang.annotation.Annotation;
          import java.lang.reflect.Field;

          public interface IFieldWiring {
              
              Class
          <? extends Annotation> annotationClass();
              
              
          void wiring(Object object, Field field);
          }

          IFieldWiring.java的實現類----DataSourceWiring.java。(該類實現只為演示用,有很多地方是可以改進的)
          import java.lang.annotation.Annotation;
          import java.lang.reflect.Field;

          public class DataSourceWiring implements IFieldWiring{

              @Override
              
          public void wiring(Object object, Field field) {
                  Object fieldObj 
          = ReflectUtils.getFieldValue(object, field.getName()); // 獲得field對應的對象
                  if (fieldObj != null{
                      
          return;
                  }

                  DataSource annotation 
          = field.getAnnotation(DataSource.class);
                  String type 
          = annotation.type();
                  String sqlMap 
          = annotation.sqlMap();
                  
          // 這里可以用緩存來實現,不用每次都去創建新的SqlMapClient對象
                  SqlMapClient sqlMapImpl = new SqlMapClient(sqlMap, type);
                  
          // 將生成SqlMapClient注入到bean對象的字段上
                  ReflectUtils.setFieldValue(object, field.getName(), SqlMapClient.class, sqlMapImpl);
              }


              @Override
              
          public Class<? extends Annotation> annotationClass() {
                  
          return DataSource.class;
              }

          }

          這里的ReflectUtils.java 也是我們自定義的,并非有Spring提供的:
          import java.lang.reflect.Field;
          import java.lang.reflect.Method;

          import org.apache.commons.lang.StringUtils;

          public class ReflectUtils {

              
          /**
               * 取得字段值
               * 
               * 
          @param obj
               * 
          @param fieldName
               * 
          @return
               
          */

              
          public static Object getFieldValue(Object obj, String fieldName) {
                  
          if (obj == null || fieldName == null || "".equals(fieldName)) {
                      
          return null;
                  }


                  Class
          <?> clazz = obj.getClass();
                  
          try {
                      String methodname 
          = "get" + StringUtils.capitalize(fieldName);
                      Method method 
          = clazz.getDeclaredMethod(methodname);
                      method.setAccessible(
          true);
                      
          return method.invoke(obj);
                  }
           catch (Exception e) {
                      
          try {
                          Field field 
          = clazz.getDeclaredField(fieldName);
                          field.setAccessible(
          true);
                          
          return field.get(obj);
                      }
           catch (Exception e1) {
                          e1.printStackTrace();
                      }

                  }

                  
          return null;
              }


              
          public static void setFieldValue(Object target, String fname, Class<?> fieldClass,
                  Object fieldObj) 
          {
                  
          if (!fieldClass.isAssignableFrom(fieldObj.getClass())) {
                      
          return;
                  }

                  Class
          <?> clazz = target.getClass();
                  
          try {
                      Method method 
          = clazz.getDeclaredMethod("set" + Character.toUpperCase(fname.charAt(0))
                          
          + fname.substring(1), fieldClass);
                      method.setAccessible(
          true);
                      method.invoke(target, fieldObj);
                  }
           catch (Exception e) {
                      
          try {
                          Field field 
          = clazz.getDeclaredField(fname);
                          field.setAccessible(
          true);
                          field.set(target, fieldObj);
                      }
           catch (Exception e1) {
                          e1.printStackTrace();
                      }

                  }

              }

          }

          已經基本大功告成了,只要將我們的DataSourceWiring.java類使用起來即可。
          MyAnnotationBeanProcessor.java,這個類主要用于為bean對象注入資源。
          import java.lang.reflect.Field;

          public class MyAnnotationBeanProcessor {

              
          /**
               * 注入資源
               * 
          @param serviceObject
               * 
          @param fieldAutoWirings // 所有實現IFieldWiring的接口的對象,我們可以在此擴展
               * 
          @throws Exception
               
          */

              
          public void wire(Object serviceObject, IFieldWiring fieldAutoWirings)
                      
          throws Exception {
                  Class
          <?> cls = serviceObject.getClass();
                  
          for (Field field : cls.getDeclaredFields()) {
                      
          for (IFieldWiring fieldAutoWiring : fieldAutoWirings) {
                          
          if (field.isAnnotationPresent(fieldAutoWiring.annotationClass())) {
                              fieldAutoWiring.wiring(serviceObject, field);
                              
          break;
                          }

                      }

                  }

              }

          }

          好了,開始我們的測試類:FieldWiringTest.java
          public class FieldWiringTest {
              
          public static void main(String args[]) throws Exception {
                  MyAnnotationBeanProcessor processor 
          = new MyAnnotationBeanProcessor();

                  MyService b 
          = new MyService();

                  processor.wire(b, 
          new DataSourceWiring()); // 注入DataSource資源
                  
                  System.out.println(b.selectForObjectFromB(
          ""null));
                  System.out.println(b.selectForObjectFromA(
          ""null));
              }

          }

          執行結果:
          SqlMapClient[sqlMap=com/annotation/sql-map-config-B.xml,type=B]
          SqlMapClient[sqlMap
          =com/annotation/sql-map-config-A.xml,type=A]

          由執行結果可以說明DataSource資源已經被我們正確的注入了。
          如果想擴展的話,只需要新建一個類實現IFieldWiring接口即可。假設叫InParamWiring.java,實現了接口定義的兩個方法后,在使用的時候,只要用以下代碼便可將資源注入了:
          MyAnnotationBeanProcessor processor = new MyAnnotationBeanProcessor();
          MyService b 
          = new MyService();
          processor.wire(b, 
          new DataSourceWiring(), new InParamWiring()); // 注入DataSource、InParam資源

          注:以上代碼重在演示,其實這個需求可以在Spring中管理兩個不同的SqlMapClient對象,然后通過Spring的自動注入實現。
          下一篇將介紹怎么通過Spring實現這樣的自定義資源注入。


          本文為原創,歡迎轉載,轉載請注明出處BlogJava
          posted on 2010-10-04 10:19 李 明 閱讀(5352) 評論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 四平市| 东至县| 西贡区| 浠水县| 安多县| 郧西县| 白水县| 大洼县| 旌德县| 广德县| 黄龙县| 阿巴嘎旗| 凤冈县| 抚松县| 兴安县| 噶尔县| 嘉义市| 门头沟区| 武乡县| 阿城市| 襄垣县| 勐海县| 玉林市| 马关县| 广东省| 商都县| 宜兰市| 汝州市| 正镶白旗| 犍为县| 保康县| 太保市| 宁远县| 七台河市| 永胜县| 呈贡县| 吉林市| 大悟县| 揭东县| 福泉市| 广河县|