模拟Spring注入的实现(循环依赖的解决)

本文通过一个妖怪吃小孩的比喻,解释了Spring注入的概念,即对象的创建和管理由Spring容器负责,开发者直接使用即可。同时,文章探讨了在存在循环依赖的情况下,如A依赖B,B依赖C,C又依赖A,Spring如何解决这种无限递归的问题。通过在BeanDefinition中添加标记来避免重复注入,从而成功解决循环依赖,确保程序正常运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring中的注入开始让我很迷,不清楚这个名词代表什么意思,怎么说呢,网上有一个很好的例子,就是说假如我是一个妖怪,我需要吃小孩,但是小孩不能凭空产生啊,需要有一个男人和一个女人,以及通过一个嘿嘿嘿的函数(小孩类构造函数),把这个小孩给造出来把,那么我只想去吃小孩,我不想去管它怎么来的,那么Spring的实现就相当于作为一个容器,假如我要吃小孩了,就从中拿出来吃就行了,不用去关心它是怎么来的,由Spring容器帮我们实现,

所以说,Spring中的注入,可以看做对被注入类的成员的声明以及实例化,也就是说,以后这个对象不用我们自己new,而是由Spring给我们自动完成了new,我们直接调用就好了,这是我们要解决的一个问题,如果不考虑太多细节的问题,可以说Spring就主要完成了这个,那么其中有个问题了,假如我们需要注入的类和其他类有依赖关系呢,或者这样说,有一个类A需要被注入,B,C是注入的成员,但是B又需要C去注入,C又需要A去注入,这样就出现了一个循环,就像三个人围成一个圈,两个人中间一只筷子,每个人都需要拿到两只筷子才能吃,这样就尬住了,任何一个人都不能吃饭,都要等,在程序中就会造成无限递归的问题,如何解决循环依赖,这就是我们的主要方向,先看工程的结构:
在这里插入图片描述
先说BeanDefinition类,这个类就是把需要被注入的类的对象,类型,封装成一个一个Bean,再通过类名-Bean的键值装到BeanFactory中,而这个BeanFactory就是我们的核心,它就处理了我之前说的操作,对被注入类中的成员进行注入 ,三个注解@Autowired注解的意思是该成员需要被注入,@component的意思该类需要被注入,@Qualifier注解是为了解决假如需要注入的成员说是一个接口类型怎么办 **,(其实还应该有一个注解是@bean注解,用来解决假如该类无法加注解怎么办,比如该类是一个jar包中的类,那么我们的解决方案就是用这个bean注解,详细问题以后再说),**下面的model层的依赖关系是: A的注入需要B ,C;B的注入需要C;C的注入需要IA类型的A;A是IA接口的实现类,B,C是一般类;
代码如下:
@Autowired

@Retention(RUNTIME)
@Target(FIELD)
public @interface Autowired {
	String value() default "";
	boolean singleton() default true;
}

@Component

@Retention(RUNTIME)
@Target(TYPE)
public @interface Component {
	String beanName() default "";
}

@Qualifier

@Retention(RUNTIME)
@Target(FIELD)
public @interface Qualifier {
	String value();
}

BeanDefinition

public class BeanDefinition {
	Class<?> klass;
	Object object;
	boolean done;
	
	BeanDefinition() {
		this.done = false;
	}

	BeanDefinition(Class<?> klass) throws Exception {
		this();
		this.klass = klass;
		this.object = klass.newInstance();
	}

	BeanDefinition(Object object) {
		this.object = object;
		this.klass = object.getClass();
	}

	boolean isDone() {
		return done;
	}

	Class<?> getKlass() {
		return klass;
	}

	void setKlass(Class<?> klass) {
		this.klass = klass;
	}

	Object getObject() {
		return object;
	}

	void setObject(Object object) {
		this.object = object;
	}

	@Override
	public String toString() {
		return klass + " : " + object;
	}

BeanFactory

package com.mec.spring.core;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.mec.spring.annotation.Autowired;
import com.mec.spring.annotation.Component;
import com.mec.spring.annotation.Qualifier;
import com.mec.util.PackageScanner;
import com.mec.util.ValueParser;

public class BeanFactory {
	private static final Map<String, BeanDefinition> beanFactory; //这个Map装的是类名-Bean
	private static final Map<String, String> beanIdMap;   //这个Map装的是用户自定义的类名-类名
	static {
		beanFactory = new ConcurrentHashMap<>();
		beanIdMap = new ConcurrentHashMap<>();
	}
	
	public BeanFactory() {
	}
	/**
	 * 扫描包路径下所有的类,并且将有component注解的类变成一个Bean,加入到beanFactory
	 * 若用户给该类定义了新的名字,就将名字-类名放入beanIdMap,再通过类名放入beanFactory
	 * @param pacakgeName
	 */
	public void initBeanFactory(String pacakgeName) {
		new PackageScanner() {    //这个是做出来的包扫描工具的应用(代码在前一次的文章里)
			@Override
			public void dealClass(Class<?> klass) {
				if (klass.isPrimitive() || klass.isInterface()
						|| klass.isAnnotation() || klass.isEnum()
						|| !klass.isAnnotationPresent(Component.class)) {
					return;
				}
				String klassName = klass.getName();
				String beanId = klassName;
				Component component = klass.getAnnotation(Component.class);  //获取带@Compoonent注解的对象
				String id = component.beanName();  //取得用户自定义的类名
				if (id.length() > 0) {
					beanId = id;
					beanIdMap.put(beanId, klassName);
				}
				
				try {
					beanFactory.put(klassName, new BeanDefinition(klass));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}.scannerPackage(pacakgeName);
	}
	/**
	 * 给Bean注入,首先检测该bean是否被注入过,如果没有,取得该类以及该类的成员
	 * 再检测该类的成员是否有Autowired注解,如果有,取得Autowired中 value的值
	 * 执行setValue()方法;
	 * @param bean
	 */
	private void setBeanValue(BeanDefinition bean) throws Exception { 
		if (bean.isDone()) {
			return;
		}
		bean.done = true;
		Class<?> klass = bean.getKlass();
		Field[] fields = klass.getDeclaredFields();
		for (Field field : fields) {
			if (!field.isAnnotationPresent(Autowired.class)) {
				continue;
			}
			Autowired autowired = field.getAnnotation(Autowired.class);
			String value = autowired.value();
			boolean singleton = autowired.singleton();
			setValue(bean, field, value.length() <= 0 ? null : value, singleton);
		}
	}
	/**
	 * 通过setBeanValue()传过来的BeanDefinition,Field,value
	 * 来给成员赋值
	 * @param bd
	 * @param field
	 * @param value
	 */
	private void setValue(BeanDefinition bd, Field field, String value, boolean singleton) throws Exception {
		//设置了value,说明为依赖关系的最后一个
		if (value != null) {
			setFieldWithValue(bd.getKlass(), bd.getObject(), field, value);
			return;
		}
		//当没有设置value,说明该成员仍然是需要注入的类
		//通过成员类型再加上包名就得到了对应的类名,然后去beanFactory和beanIdMap里面找对应的类
		Class<?> type = field.getType();
		BeanDefinition bean = getBeanDefinition(type.getName());
	
		if (bean == null) {
			//如果找不到,去找它的父类是不是某个接口
			BeanDefinition[] beans = searchBeanBySuperType(type);
			if (beans.length == 1) {
				bean = beans[0];
			}
			//存在@Qualifier注解的成员才需要去找它的接口实现类,若没有直接抛出异常
			//若存在的话一个实现类那么就将这个类注入,若存在多个实现类,根据@Qualifier注解中value的值来确定是哪个实现类
			if (beans.length <= 0 || !field.isAnnotationPresent(Qualifier.class)) {
				throw new Exception("类" + bd.getKlass() + "的成员" + field.getName() + "注入失败!");
			} else {
				Qualifier qualifier = field.getAnnotation(Qualifier.class);
				String beanName = qualifier.value();
				bean = getBeanDefinition(beanName);
				if (bean == null) {
					throw new Exception("类" + bd.getKlass() + "的成员" + field.getName() + "注入失败!");
				}
			}
		}
		if (!singleton) {
			bean = new BeanDefinition(type);
		}
		if (!bean.isDone()) {
			setBeanValue(bean);
		}
		setFieldValue(bd.getObject(), bd.getKlass(), field, bean.getObject());
	}
	/**
	 * 如果没有在beanFactory和beanidMap中找到该类
	 * 那么就找在beanfactory中是否有它的实现类,如果有
	 * 就把它的所有实现类放入一个数组,然后返回这个数组
	 * 那么就在这里找
	 * @param klass
	 * @return
	 */
	private BeanDefinition[] searchBeanBySuperType(Class<?> klass) {
		List<BeanDefinition> beanList = new ArrayList<>();
		
		for (BeanDefinition bean : beanFactory.values()) {
			Class<?> beanClass = bean.getKlass();
			if (klass.isAssignableFrom(beanClass)) {
				beanList.add(bean);
			}
		}
		BeanDefinition[] beans = new BeanDefinition[beanList.size()];
		beanList.toArray(beans);
		
		return beans;
	}
	
	/**
	 * 将String类型的value转换为该类成员类型的value
	 * @param klass
	 * @param object
	 * @param field
	 * @param value
	 */
	private void setFieldWithValue(Class<?> klass, Object object, Field field, String value) 
			throws Exception {
		Class<?> type = field.getType();
		Object val = ValueParser.stringToObject(type, value);
		setFieldValue(object, klass, field, val);
	}
	/**
	 * 用上一步 传过来的该类以及该类的对象,成员,还有转换过类型的value
	 * 给该类的成员赋值
	 * @param object
	 * @param klass
	 * @param field
	 * @param val
	 */
	private void setFieldValue(Object object, Class<?> klass, Field field, Object val) throws Exception {
		Class<?> type = field.getType();
		String fieldName = field.getName();
		String methodName = "set" + fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
		try {
			//假如该类中有set方法,那么就反射机制执行他的set方法赋值
			Method method = klass.getDeclaredMethod(methodName, new Class<?>[] {type});
			method.invoke(object, val);
		} catch (Exception e) {
			//假如没有,就去直接用反射机制直接赋值
			field.setAccessible(true);
			field.set(object, val);
		}
	}
	
	/**
	 * 通过beanid在beanFactory中找对应的bean
	 * 如果没找到再去beanIdMap中找是否有对应的classname
	 * @param beanId
	 * @return
	 * @throws Exception
	 */
	private BeanDefinition getBeanDefinition(String beanId) throws Exception {
		BeanDefinition bean = beanFactory.get(beanId);
		if (bean == null) {
			String className = beanIdMap.get(beanId);
			if (className == null) {
				return null;
			}
			bean = beanFactory.get(className);
		}
		return bean;
	}
	
	//下面两个方法都是提供给外部调用的,用来给某个类进行注入
	@SuppressWarnings("unchecked")
	public <T> T getBean(String beanId) throws Exception {
		BeanDefinition bean = getBeanDefinition(beanId);
		setBeanValue(bean);	
		return (T) bean.getObject();
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getBean(Class<?> klass) throws Exception {
		String beanId = klass.getName();
		BeanDefinition bd = beanFactory.get(beanId);
		if (bd == null) {
			throw new Exception("类" + klass.getName() + "不存在!");
		}
		setBeanValue(bd);	
		return (T) bd.getObject();
	}
	
}

IA

public interface IA {

}

A

@Component
public class A implements IA {
	@Autowired
	private B b;
	@Autowired // (singleton=false)
	private C c;

	public A() {
		System.out.println("A被构造!");
	}
	
	public C getC() {
		return c;
	}
	
	@Override
	public String toString() {
		return "这就是A,其中b:" + b + ", c:" + c;
	}
}

B

@Component
public class B {
	@Autowired
	private C c;
	
	public B() {
	}
	
	public C getC() {
		return c;
	}
	
	@Override
	public String toString() {
		return "这就是B!";
	}
	
}

C

@Component
public class C {
	@Autowired
	@Qualifier("aa")
	private IA a;
	
	public C() {
		System.out.println("C被构造!");
	}

	@Override
	public String toString() {
		return "这就是C!其中的a是" + a.getClass().getSimpleName() + "类型的!";
	}
}

AA

	
	public AA() {
		System.out.println("AA被构造!");
	}

	@Override
	public String toString() {
		return "AA的对象!";
	}
	
}

Test

public class Test {

	public static void main(String[] args) {
		BeanFactory beanFactory = new BeanFactory();
		beanFactory.initBeanFactory("com.mec.spring.test.model");
		
		try {
			A a = beanFactory.getBean(A.class);
			System.out.println(a);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

结果:
在这里插入图片描述
从结果可以清晰的看到A类的注入已经完成了,而且也没用出现循环依赖的无限递归,这是因为我们对每个Bean都加了一个Boolean类型的成员,用来记录该成员是否被注入过,如果被注入过,下次需要注入的时候,就直接用将该成员传过去,不用再进行注入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值