使用Java注解模擬spring ioc容器過程解析
使用注解,簡(jiǎn)單模擬spring ioc容器。通過注解給對(duì)象屬性注入值。
項(xiàng)目結(jié)構(gòu)

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 控制反轉(zhuǎn)容器,在加載類的時(shí)候創(chuàng)建 HashMap , 并存入指定對(duì)象
*/
private static Map<String, Object> ioc;
static {
try {
// 初始化 IOC 容器
ioc = new HashMap<String, Object>();
// 反射獲得 Class 對(duì)象
Class<?> clazz = Class.forName("priv.haidnor.pojo.Person");
// 獲取指定注解
Component componentClass = clazz.getAnnotation(Component.class);
// 獲取指定注解的值
String key = componentClass.name();
// 通過反射創(chuàng)建對(duì)象
Object object = clazz.newInstance();
ioc.put(key, object);
// 獲取 Java Bean 所有的字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 字段類型
Class<?> type = field.getType();
// 根據(jù)字段名生成 set 方法
String filedName = field.getName();
String methodName = produceSetMethodName(filedName);
// 獲得 Value 注解
Value valueAnnotation = field.getAnnotation(Value.class);
// 獲得注解的值
String theValue = valueAnnotation.value();
// 構(gòu)造 Method 對(duì)象
Method method = clazz.getDeclaredMethod(methodName, field.getType());
// 將注解參數(shù)轉(zhuǎn)換類型
Object value = typeConversion(field.getType(), theValue);
// 執(zhí)行 set 方法
method.invoke(object, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 類型轉(zhuǎn)換。將 String 字符串轉(zhuǎn)換為指定數(shù)據(jù)類型類型的值
* @param typeClass 字段類型
* @param value 注解值
* @return 字符串轉(zhuǎn)換為指定數(shù)據(jù)類型類型的值
*/
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);
}
/**
* 從容器中獲得指定對(duì)象
* @param name 對(duì)象名稱
* @return IOC 容器中的對(duì)象
*/
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("中國(guó)")
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 +
'}';
}
}
測(cè)試類
import priv.haidnor.ioc.ApplicationContext;
import priv.haidnor.pojo.Person;
/**
* 測(cè)試類
*/
public class Demo {
public static void main(String[] args) {
Person person = (Person) ApplicationContext.getBean("man");
System.out.println(person);
}
}
運(yùn)行程序后,控制臺(tái)輸出對(duì)象信息,可以看到從ioc容器中拿出的對(duì)象已經(jīng)成功被注解賦值

備注
內(nèi)置注解
@Override:定義在java.lang.Override中,此注釋只適用于修辭方法,表示一個(gè)方法聲明打算重寫超類中的另一個(gè)方法聲明.
@Deprecated:定義在java.lang.Deprecated中,此注釋可以用于修辭方法,屬性,類,表示不鼓勵(lì)程序員使用這樣的元素,通常是因?yàn)樗芪kU(xiǎn)或者存在更好的選擇.
@SuppressWarnings:定義在java.lang.SuppressWarnings中,用來抑制編譯時(shí)的警告信息.口與前兩個(gè)注釋有所不同,你需要添加一個(gè)參數(shù)才能正確使用,這些參數(shù)都是已經(jīng)定義好了的,我們選擇性的使用就好了.
- @SuppressWarnings ("all")
- @SuppressWarnings ("unchecked")
- @SuppressWarnings (value={"unchecked","deprecation"})
- 等等……
4個(gè)元注解
元注解的作用就是負(fù)責(zé)注解其他注解,Java定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型,他們被用來提供對(duì)其他annotation類型作說明.
這些類型和它們所支持的類在java.lang.annotation包中可以找到
@Target:用于描述注解的使用范圍(即:作用域,被描述的注解可以用在什么地方)
@Target(value = {ElementType.TYPE,ElementType.CONSTRUCTOR})
@Target(value = ElementType.TYPE)
@Target(ElementType.TYPE)
類,接口(包括注釋類型)或枚舉聲明
TYPE
字段聲明(包括枚舉常量)
FIELD
方法聲明
METHOD
形式參數(shù)聲明
PARAMETER
構(gòu)造聲明
CONSTRUCTOR
局部變量聲明
LOCAL_VARIABLE
注解類型聲明
ANNOTATION_TYPE
包聲明
PACKAGE
類型參數(shù)聲明 @since 1.8
TYPE_PARAMETER
使用類型 @since 1.8
TYPE_USE
@Retention:表示需要在什么級(jí)別保存該注釋信息,用于描述注解的生命周期 (SOURCE<CLASS<RUNTIME)
@Retention(value = RetentionPolicy.CLASS) @Retention(RetentionPolicy.CLASS) 注解將被編譯階段丟棄 SOURCE 注解將由編譯器記錄在類文件中,但VM不必在運(yùn)行時(shí)保留它們。這是默認(rèn)行為。 CLASS 注解由編譯器記錄在類文件中,并在運(yùn)行時(shí)由VM保留,因此可以通過反射方式讀取它們 RUNTIME
@Document:說明該注解將被包含在javadoc中
@lnherited:說明子類可以繼承父類中的該注解
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java+opencv實(shí)現(xiàn)人臉識(shí)別功能
這篇文章主要介紹了java+opencv實(shí)現(xiàn)人臉識(shí)別功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05
SpringBoot2.x版本中,使用SpringSession踩的坑及解決
這篇文章主要介紹了SpringBoot2.x版本中,使用SpringSession踩的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Kotlin與Java 泛型缺陷和應(yīng)用場(chǎng)景詳解
這篇文章主要為大家介紹了Kotlin與Java 泛型缺陷和應(yīng)用場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
PowerJob的OmsLogHandler工作流程源碼解析
這篇文章主要為大家介紹了PowerJob的OmsLogHandler工作流程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項(xiàng)目
這篇文章主要介紹了Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項(xiàng)目,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
SpringBoot+Security 發(fā)送短信驗(yàn)證碼的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot+Security 發(fā)送短信驗(yàn)證碼的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05

