就 Spring如何解决bean之间的循环依赖的问题 问题, 做简要代码实现解决对象之间的循环依赖问题
。配合 BGDI 组件实现简单 Spring IOC容器及其依赖注入特性。结合 spring的scope为prototype的bean的正确使用方法 实现 bean 的多实例注入
- Spring是通过递归的方式获取目标bean及其所依赖的bean的;
- Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。
结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。
public class ServiceA {
private ServiceB serviceB;
public String query() {
System.out.println("ServiceA query...");
return "A";
}
}
public class ServiceB {
private ServiceA serviceA;
public String query() {
System.out.println("ServiceB query...");
return "B";
}
}
// 对象实例化结果存储容器
private static final HashMap<String, Object> CLASSES_MAP = Maps.newHashMap();
// 通过注解获取需要注入的对象信息
private static final List<Class<?>> INIT_CLASSES = Lists.newArrayList(ServiceA.class, ServiceB.class);
public static void main(String[] args) throws Exception {
System.out.println("加载bean...");
for (Class<?> clz : INIT_CLASSES) {
injection(clz);
}
System.out.println("执行方法...");
for (Class<?> clz : INIT_CLASSES) {
String clzName = clz.getName();
if (!CLASSES_MAP.containsKey(clzName)) {
System.out.println(String.format("容器中不包含clzName=[%s]", clzName));
continue;
}
Object object = CLASSES_MAP.get(clzName);
Method[] declaredMethods = clz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
declaredMethod.invoke(object);
}
System.out.println();
}
}
private static void injection(Class<?> clz) throws Exception {
String clzName = clz.getName();
if (!CLASSES_MAP.containsKey(clzName)) {
// 实例化对象
Object instance = clz.newInstance();
CLASSES_MAP.put(clzName, instance);
Field[] declaredFields = clz.getDeclaredFields();
for (Field declaredField : declaredFields) {
Class<?> fldClz = declaredField.getType();
String fldTypeClzName = fldClz.getName();
// 如果属性未被实例化, 先实例化属性并注入到容器
if (!CLASSES_MAP.containsKey(fldTypeClzName)) {
// 递归实例化属性并注入
injection(fldClz);
}
declaredField.setAccessible(true);
// 注入属性, 设置对象属性值
declaredField.set(instance, CLASSES_MAP.get(fldTypeClzName));
}
}
}