某節(jié)實(shí)驗(yàn)課的任務(wù)是練習(xí)使用spring的ioc宏榕,因?yàn)橹坝眠^黄橘,感覺也沒啥意思呐矾,就想了以下他的實(shí)現(xiàn)原理,然后自己使用java反射機(jī)制實(shí)現(xiàn)了一個簡單的ioc容器嘲叔。以下對原理進(jìn)行簡單的說明亡呵,完整的代碼及用法詳見xmfaly/simpleioc
首先定義@Autowired注解用于自動注入
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
Class<?> value() default Class.class;
String name() default "";
}
建立一個Container
容器類
建立兩個map
分別保存類名和bean、對象名和類名的關(guān)系
// 保存所有bean 格式為 類名 : bean
private Map<String, Object> beans;
// 存儲對象和類名的關(guān)系 對象名 :bean
private Map<String, Object> beanKeys;
這里為了安全起見硫戈,使用ConcurrentHashMap()
實(shí)例化這兩個map
public Container(){
beans = new ConcurrentHashMap<String, Object>();
beanKeys = new ConcurrentHashMap<String, String>();
}
向容器內(nèi)注冊bean锰什,這里我重載了三種形式,當(dāng)然也可以更多丁逝,關(guān)鍵看使用的場景了汁胆。
/**
* 以class的形式注冊
*/
public Object registerBean(Class<?> cls) {
String className = cls.getName();
Object bean = null;
try {
bean = cls.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
beans.put(className, bean);
//不指定對象名的情況下類名和對象名相同
beanKeys.put(className, bean);
return bean;
}
/**
* 以bean的形式注冊
*/
public Object registerBean(Object bean) {
String className = bean.getClass().getName();
beans.put(className, bean);
beanKeys.put(className, bean);
return bean;
}
/**
* 以帶對象名的class形式注冊
*/
public Object registerBean(String name, Class<?> cls) {
String className = cls.getName();
Object bean = null;
try {
bean = cls.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
beans.put(className, bean);
beanKeys.put(name, bean);
return bean;
}
/**
* 注冊一個帶名稱的Bean到容器中
*/
public Object registerBean(String name, Object bean) {
String className = bean.getClass().getName();
beans.put(className, bean);
beanKeys.put(name, bean);
return bean;
}
從容器中取出bean
/**
* 通過 Class 對象獲取bean
*/
public <T> T getBean(Class<?> cls) {
String className = cls.getName();
Object object = beans.get(className);
if (null != object) {
return (T) object;
}
return null;
}
/**
* 通過對象名獲取 bean
*/
public <T> T getBeanByName(String name) {
Object object = beanKeys.get(name);;
if (null != object) {
return (T) object;
}
return null;
}
在容器啟動的時候遍歷容器內(nèi)的所有bean對bean進(jìn)行注入
/**
* 初始化
*/
public void init() {
Iterator<Map.Entry<String, Object>> it = beans.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> entry = it.next();
Object object = entry.getValue();
injection(object);
}
}
其中使用到的方法的實(shí)現(xiàn)
/**
* 注入
*/
public void injection(Object object) {
Field[] fields = object.getClass().getDeclaredFields();
try {
//遍歷所有屬性尋找@Autowired注解
for (Field field : fields) {
Autowired autowired = field.getAnnotation(Autowired.class);
if (null != autowired) {
// 要注入的字段
Object autoWritedField = null;
String name = autowired.name();
if (!name.equals("")) {
Object bean = beanKeys.get(name);
if (null != bean ) {
autoWritedField = bean;
}
if (null == autoWritedField) {
throw new RuntimeException("Unable to autoWrited " + name);
}
} else {
if (autowired.value() == Class.class) {
//該屬性的Type
autoWritedField = recursiveAssembly(field.getType());
} else {
// 指定裝配的類
autoWritedField = this.getBean(autowired.value());
if (null == autoWritedField) {
autoWritedField = recursiveAssembly(autowired.value());
}
}
}
if (null == autoWritedField) {
throw new RuntimeException("Unable to autoWrited " + field.getType().getCanonicalName());
}
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(object, autoWritedField);
field.setAccessible(accessible);
}
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 修復(fù)沒有指定注解及默認(rèn)注入的情況
*/
private Object recursiveAssembly(Class<?> cls) {
if (null != cls) {
return this.registerBean(cls);
}
return null;
}
寫個測試測試3中注入類型
public class TestIoc {
class A{
@Autowired(name = "myvalue")
private Integer value;
@Autowired(name = "str")
private String myStr;
@Autowired(value = String.class)
private String myStr2;
@Autowired
public String myStr3;
public void show(){
System.out.println("value: " + value);
System.out.println("str: " + myStr);
System.out.println(myStr2 == null);
System.out.println(myStr3 == null);
}
}
@Test
public void test(){
Container c = new Container();
c.registerBean("a",new A());
c.registerBean("str","注入成功");
c.registerBean("myvalue",2333);
c.initWired();
A a = c.getBeanByName("a");
a.show();
}
}
測試成功
value: 2333
str: 注入成功
false
false