歡迎您光臨本站 註冊首頁

使用Java註解模擬spring ioc容器過程解析

←手機掃碼閱讀     wooen @ 2020-07-08 , reply:0

使用註解,簡單模擬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:說明子類可以繼承父類中的該註解


[wooen ] 使用Java註解模擬spring ioc容器過程解析已經有275次圍觀

http://coctec.com/docs/java/show-post-241839.html