使用Java註解模擬spring ioc容器過程解析
使用註解,簡單模擬spring ioc容器。通過註解給物件屬性注入值。
專案結構
annotation 包,用於存放自定義註解
Component 註解表示該類為元件類,並需要宣告名字
package priv.haidnor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 元件 */ @Target(value = ElementType.TYPE) @Retention(value = RetentionPolicy.RUNTIME) public @interface Component { String name(); }
Value 註解用於給類的屬性賦值
package priv.haidnor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 欄位值 */ @Target(value = ElementType.FIELD) @Retention(value = RetentionPolicy.RUNTIME) public @interface Value { String value(); }
ioc 包
package priv.haidnor.ioc; import priv.haidnor.annotation.Component; import priv.haidnor.annotation.Value; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; public class ApplicationContext { /** * IOC 控制反轉容器,在載入類的時候建立 HashMap,並存入指定物件 */ private static Map<String,Object> ioc; static { try { // 初始化 IOC 容器 ioc = new HashMap<String,Object>(); // 反射獲得 Class 物件 Class<?> clazz = Class.forName("priv.haidnor.pojo.Person"); // 獲取指定註解 Component componentClass = clazz.getAnnotation(Component.class); // 獲取指定註解的值 String key = componentClass.name(); // 通過反射建立物件 Object object = clazz.newInstance(); ioc.put(key,object); // 獲取 Java Bean 所有的欄位 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // 欄位型別 Class<?> type = field.getType(); // 根據欄位名生成 set 方法 String filedName = field.getName(); String methodName = produceSetMethodName(filedName); // 獲得 Value 註解 Value valueAnnotation = field.getAnnotation(Value.class); // 獲得註解的值 String theValue = valueAnnotation.value(); // 構造 Method 物件 Method method = clazz.getDeclaredMethod(methodName,field.getType()); // 將註解引數轉換型別 Object value = typeConversion(field.getType(),theValue); // 執行 set 方法 method.invoke(object,value); } } catch (Exception e) { e.printStackTrace(); } } /** * 型別轉換。將 String 字串轉換為指定資料型別型別的值 * @param typeClass 欄位型別 * @param value 註解值 * @return 字串轉換為指定資料型別型別的值 */ private static Object typeConversion(Class<?> typeClass,String value) { if (typeClass == int.class || typeClass == Integer.class) { if (value == null) { return 0; } return Integer.valueOf(value); } else if (typeClass == short.class) { if (value == null) { return 0; } return Short.valueOf(value); } else if (typeClass == byte.class) { if (value == null) { return 0; } return Short.valueOf(value); } else if (typeClass == double.class) { if (value == null) { return 0; } return Double.valueOf(value); } else if (typeClass == long.class) { if (value == null) { return 0; } return Long.valueOf(value); } else if (typeClass == String.class) { if (value == null) { return ""; } return value; } else if (typeClass == Boolean.class) { if (value == null) { return false; } return Boolean.valueOf(value); } else if (typeClass == BigDecimal.class) { if (value == null) { return new BigDecimal(0); } return new BigDecimal(value + ""); } else { return typeClass.cast(value); } } /** * 拼接字串,生成 set 方法名 * @param filedName 欄位名 * @return set方法名,例如傳入"name",則返回"setName" */ private static String produceSetMethodName(String filedName) { return "set" + filedName.substring(0,1).toUpperCase() + filedName.substring(1); } /** * 從容器中獲得指定物件 * @param name 物件名稱 * @return IOC 容器中的物件 */ public static Object getBean(String name) { return ioc.get(name); } }
pojo 包
package priv.haidnor.pojo; import priv.haidnor.annotation.Component; import priv.haidnor.annotation.Value; @Component(name = "man") public class Person { @Value("張三") private String name; @Value("男") private String gender; @Value("中國") private String country; @Value("23") private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ",gender='" + gender + '\'' + ",country='" + country + '\'' + ",age=" + age + '}'; } }
測試類
import priv.haidnor.ioc.ApplicationContext; import priv.haidnor.pojo.Person; /** * 測試類 */ public class Demo { public static void main(String[] args) { Person person = (Person) ApplicationContext.getBean("man"); System.out.println(person); } }
執行程式後,控制檯輸出物件資訊,可以看到從ioc容器中拿出的物件已經成功被註解賦值
備註
內建註解
@Override:定義在java.lang.Override中,此註釋只適用於修辭方法,表示一個方法宣告打算重寫超類中的另一個方法宣告.
@Deprecated:定義在java.lang.Deprecated中,此註釋可以用於修辭方法,屬性,類,表示不鼓勵程式設計師使用這樣的元素,通常是因為它很危險或者存在更好的選擇.
@SuppressWarnings:定義在java.lang.SuppressWarnings中,用來抑制編譯時的警告資訊.口與前兩個註釋有所不同,你需要新增一個引數才能正確使用,這些引數都是已經定義好了的,我們選擇性的使用就好了.
- @SuppressWarnings ("all")
- @SuppressWarnings ("unchecked")
- @SuppressWarnings (value={"unchecked","deprecation"})
- 等等……
4個元註解
元註解的作用就是負責註解其他註解,Java定義了4個標準的meta-annotation型別,他們被用來提供對其他annotation型別作說明.
這些型別和它們所支援的類在java.lang.annotation包中可以找到
@Target:用於描述註解的使用範圍(即:作用域,被描述的註解可以用在什麼地方)
@Target(value = {ElementType.TYPE,ElementType.CONSTRUCTOR}) @Target(value = ElementType.TYPE) @Target(ElementType.TYPE) 類,介面(包括註釋型別)或列舉宣告 TYPE 欄位宣告(包括列舉常量) FIELD 方法宣告 METHOD 形式引數宣告 PARAMETER 構造宣告 CONSTRUCTOR 區域性變數宣告 LOCAL_VARIABLE 註解型別宣告 ANNOTATION_TYPE 包宣告 PACKAGE 型別引數宣告 @since 1.8 TYPE_PARAMETER 使用型別 @since 1.8 TYPE_USE
@Retention:表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期 (SOURCE<CLASS<RUNTIME)
@Retention(value = RetentionPolicy.CLASS) @Retention(RetentionPolicy.CLASS) 註解將被編譯階段丟棄 SOURCE 註解將由編譯器記錄在類檔案中,但VM不必在執行時保留它們。這是預設行為。 CLASS 註解由編譯器記錄在類檔案中,並在執行時由VM保留,因此可以通過反射方式讀取它們 RUNTIME
@Document:說明該註解將被包含在javadoc中
@lnherited:說明子類可以繼承父類中的該註解
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。