献上一段自己写的极其简陋版的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());
}
}