獻上一段自己寫的極其簡陋版的ioc容器的實現,幫助大家瞭解spring基本原理
步驟:
1、首先自定義註解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponent {
}
然後創建緩存(我這裏只有兩個個緩存),兩個緩存主要起到單例和解決循環依賴的作用,一級緩存主要存放已經創建好並且已經完全屬性賦值好的bean,二級緩存主要存放實例化但是未屬性賦值的bean,注意:這裏一級緩存和二級緩存相同beanName存放的bean都是指向同一個內存地址,只是bean沒完成創建好時暫時存放在二級緩存中
public final static Map<String, Object> oneCache = new ConcurrentHashMap<>();
public final static Map<String, Object> twoCache = new ConcurrentHashMap<>();
下面是兩個用來測試的bean,並且相互注入
@MyComponent
@Setter
@Getter
public class Cat {
@MyAutowired
private Dog dog;
}
@MyComponent
@Setter
@Getter
public class Dog {
@MyAutowired
private Cat cat;
private String name;
private int age;
public Dog() {
this.name="dog";
this.age=10;
}
@Override
public String toString() {
return "Dog{" +
"cat=" + cat +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
下面是我自己實現的getBean,已經解決循環依賴問題,代碼不難,主要是使用一級緩存和二級緩存處理單例和循環依賴問題,然後利用反射實現bean的創建及屬性的賦值
public class MyGetBean {
public final static Map<String, Object> oneCache = new ConcurrentHashMap<>();
public final static Map<String, Object> twoCache = new ConcurrentHashMap<>();
public Object getBean(Class clazz) throws Exception {
if (clazz.isAnnotationPresent(MyComponent.class)) {
String simpleName = clazz.getSimpleName();
StringBuilder beanName = new StringBuilder(simpleName);
beanName.replace(0, 1, simpleName.substring(0, 1).toLowerCase());
Object bean = getSingleton(beanName.toString());
if (bean != null) {
return bean;
}
bean = createBean(clazz, beanName.toString());
return bean;
} else {
throw new RuntimeException("容器沒找到該類型的bean");
}
}
private Object getSingleton(String beanName) {
Object one = oneCache.get(beanName);
if (one == null) {
one = twoCache.get(beanName);
} else {
twoCache.remove(beanName);
}
return one;
}
private synchronized Object createBean(Class clazz, String beanName) throws Exception {
Object bean = oneCache.get(beanName);
if (bean == null) {
bean = clazz.newInstance();
twoCache.put(beanName, bean);
for (Field field : clazz.getDeclaredFields()) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
if (field.isAnnotationPresent(MyAutowired.class)) {
Class<?> type = field.getType();
Object inject = getBean(type);
field.set(bean, inject);
}
}
oneCache.put(beanName, bean);
}
return bean;
}
}
測試,運行無錯誤
public class Test {
@org.junit.Test
public void test() throws Exception {
MyGetBean myGetBean = new MyGetBean();
Cat bean = (Cat) myGetBean.getBean(Cat.class);
System.out.println(bean.getDog().toString());
}
}