当前位置: 首页 > news >正文

手写一个Spring:一、IOC容器

前置
首先先引入依赖:

    <dependencies>// 辅助加载读取文件<dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency>// 快速添加构造方法,get set等,简化代码<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.36</version></dependency></dependencies>

一、建立一个最基本的基于xml配置文件的IOC容器

功能说明:
首先需要读取xml配置文件,然后注入bean

思路:

  1. 读取xml文件配置
  2. 创建BeanDefinition(bean的定义,由于不知道bean的具体类型,引入BeanDefinition记录bean的信息)
  3. 根据BeanDefinition中的信息,结合反射,创建bean

代码实现:

  • 构建xml文件信息(放在项目的resources文件下)
<?xml version="1.0" encoding="UTF-8" ?>
<beans><bean id = "xxxid" class = "com.minis.xxxclass"></bean>
</beans>
  • BeanDefinition的定义以及初始容器的构造
public class BeanDefinition {private String id;private String className;public BeanDefinition(String id, String className) {this.id = id;this.className = className;}//省略getter和setter
public class ClassPathXmlApplicationContext {// 保存BeanDefinitionprivate List<BeanDefinition> beanDefinitions = new ArrayList<>();// ioc容器,存储beanprivate Map<String, Object> singletons = new HashMap<>();//构造器获取外部配置,解析出Bean的定义,形成内存映像public ClassPathXmlApplicationContext(String fileName) {this.readXml(fileName);this.instanceBeans();}private void readXml(String fileName) {SAXReader saxReader = new SAXReader();try {URL xmlPath =
this.getClass().getClassLoader().getResource(fileName);Document document = saxReader.read(xmlPath);Element rootElement = document.getRootElement();//对配置文件中的每一个<bean>,进行处理for (Element element : (List<Element>) rootElement.elements()) {//获取Bean的基本信息String beanID = element.attributeValue("id");String beanClassName = element.attributeValue("class");BeanDefinition beanDefinition = new BeanDefinition(beanID,
beanClassName);//将Bean的定义存放到beanDefinitionsbeanDefinitions.add(beanDefinition);}}}//利用反射创建Bean实例,并存储在singletons中private void instanceBeans() {for (BeanDefinition beanDefinition : beanDefinitions) {try {singletons.put(beanDefinition.getId(),
Class.forName(beanDefinition.getClassName()).newInstance());}}}//这是对外的一个方法,让外部程序从容器中获取Bean实例,会逐步演化成核心方法public Object getBean(String beanName) {return singletons.get(beanName);}
}

测试

测试bean是否能注入成功

  1. 定义结构
    在这里插入图片描述
    在这里插入图片描述
public interface AService {void sayHello();
}
public class AServiceImpl implements AService {public void sayHello() {System.out.println("a service 1 say hello");}
}

xml:

<?xml version="1.0" encoding="UTF-8" ?>
<beans><bean id = "aservice" class = "com.minis.test.AServiceImpl"></bean>
</beans>
public class Test1 {public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");AService aService = (AService)ctx.getBean("aservice");aService.sayHello();}
}

在这里插入图片描述
可以看到,即便在主方法中,没有创建AServiceImpl类,依然能够执行其方法,因为在读取配置的时候已经容器中创建了对应实例。

解耦

先定义一些工厂接口和资源接口(由于上述代码只针对xml,所以添加接口方便扩展)

public interface BeanFactory {Object getBean(String beanName) throws BeansException;void registerBeanDefinition(BeanDefinition beanDefinition);
}
public interface Resource extends Iterator<Object> {
}

加载xml文件

public class ClassPathXmlResource implements Resource{Document document;Element rootElement;Iterator<Element> elementIterator;public ClassPathXmlResource(String fileName) {SAXReader saxReader = new SAXReader();URL xmlPath = this.getClass().getClassLoader().getResource(fileName);//将配置文件装载进来,生成一个迭代器,可以用于遍历try {this.document = saxReader.read(xmlPath);this.rootElement = document.getRootElement();this.elementIterator = this.rootElement.elementIterator();}}public boolean hasNext() {return this.elementIterator.hasNext();}public Object next() {return this.elementIterator.next();}
}

解析xml文件

public class XmlBeanDefinitionReader {BeanFactory beanFactory;public XmlBeanDefinitionReader(BeanFactory beanFactory) {this.beanFactory = beanFactory;}public void loadBeanDefinitions(Resource resource) {while (resource.hasNext()) {Element element = (Element) resource.next();String beanID = element.attributeValue("id");String beanClassName = element.attributeValue("class");BeanDefinition beanDefinition = new BeanDefinition(beanID, beanClassName);this.beanFactory.registerBeanDefinition(beanDefinition);}}
}

最后我们开头制作的ioc容易就可以存在一个单例工厂(还有其他类型的工厂,所以定义了工厂接口)中

public class SimpleBeanFactory implements BeanFactory{private List<BeanDefinition> beanDefinitions = new ArrayList<>();private List<String> beanNames = new ArrayList<>();private Map<String, Object> singletons = new HashMap<>();public SimpleBeanFactory() {}//getBean,容器的核心方法public Object getBean(String beanName) throws BeansException {//先尝试直接拿Bean实例Object singleton = singletons.get(beanName);//如果此时还没有这个Bean的实例,则获取它的定义来创建实例if (singleton == null) {int i = beanNames.indexOf(beanName);if (i == -1) {throw new BeansException();}else {//获取Bean的定义BeanDefinition beanDefinition = beanDefinitions.get(i);try {singleton = Class.forName(beanDefinition.getClassName()).newInstance();}//注册Bean实例singletons.put(beanDefinition.getId(), singleton);}}return singleton;}public void registerBeanDefinition(BeanDefinition beanDefinition) {this.beanDefinitions.add(beanDefinition);this.beanNames.add(beanDefinition.getId());}
}

二、容器增强

现在我们将上述过程进行拆分:

  1. 增加单例Bean的接口定义,把所有bean默认为单例模式
  2. 预留事件监听接口,方便后续进一步解读代码逻辑
  3. 扩展BeanDefinition,增加一些属性,现在的BeanDefinition只有id和className

接下来定义一些接口和实现,具体的存放位置可以自己看情况放置

构建单例bean

public interface BeanFactory {Object getBean(String beanName) throws BeansException;Boolean containsBean(String name);void registerBean(String beanName, Object obj);
}
public interface SingletonBeanRegistry {void registerSingleton(String beanName, Object singletonObject);Object getSingleton(String beanName);boolean containsSingleton(String beanName);String[] getSingletonNames();
}

接口已经定义好了,接下来我们定义一个默认的实现类。

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {//容器中存放所有bean的名称的列表protected List<String> beanNames = new ArrayList<>();//容器中存放所有bean实例的mapprotected Map<String, Object> singletons = new ConcurrentHashMap<>(256);public void registerSingleton(String beanName, Object singletonObject) {synchronized (this.singletons) {this.singletons.put(beanName, singletonObject);this.beanNames.add(beanName);}}public Object getSingleton(String beanName) {return this.singletons.get(beanName);}public boolean containsSingleton(String beanName) {return this.singletons.containsKey(beanName);}public String[] getSingletonNames() {return (String[]) this.beanNames.toArray();}protected void removeSingleton(String beanName) {synchronized (this.singletons) {this.beanNames.remove(beanName);this.singletons.remove(beanName);}}
}

最后就是单例bean工厂的实现

public class SimpleBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory{private Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);public SimpleBeanFactory() {}//getBean,容器的核心方法public Object getBean(String beanName) throws BeansException {//先尝试直接拿bean实例Object singleton = this.getSingleton(beanName);//如果此时还没有这个bean的实例,则获取它的定义来创建实例if (singleton == null) {//获取bean的定义BeanDefinition beanDefinition = beanDefinitions.get(beanName);if (beanDefinition == null) {throw new BeansException("No bean.");}try {singleton = Class.forName(beanDefinition.getClassName()).newInstance();}//新注册这个bean实例this.registerSingleton(beanName, singleton);}return singleton;}public void registerBeanDefinition(BeanDefinition beanDefinition) {this.beanDefinitions.put(beanDefinition.getId(), beanDefinition);}public Boolean containsBean(String name) {return containsSingleton(name);}public void registerBean(String beanName, Object obj) {this.registerSingleton(beanName, obj);}
}

注入的属性设置

下面是构造器注入和setter注入的模型,后面在bean注入的时候会用到

public class ArgumentValue {private Object value;private String type;private String name;public ArgumentValue(Object value, String type) {this.value = value;this.type = type;}public ArgumentValue(Object value, String type, String name) {this.value = value;this.type = type;this.name = name;}//省略getter和setter
}
public class PropertyValue {private final String name;private final Object value;public PropertyValue(String name, Object value) {this.name = name;this.value = value;}//省略getter
}
  • ArgumentValues类
public class ArgumentValues {private final Map<Integer, ArgumentValue> indexedArgumentValues = new HashMap<>(0);private final List<ArgumentValue> genericArgumentValues = new LinkedList<>();public ArgumentValues() {}private void addArgumentValue(Integer key, ArgumentValue newValue) {this.indexedArgumentValues.put(key, newValue);}public boolean hasIndexedArgumentValue(int index) {return this.indexedArgumentValues.containsKey(index);}public ArgumentValue getIndexedArgumentValue(int index) {return this.indexedArgumentValues.get(index);}public void addGenericArgumentValue(Object value, String type) {this.genericArgumentValues.add(new ArgumentValue(value, type));}private void addGenericArgumentValue(ArgumentValue newValue) {if (newValue.getName() != null) {for (Iterator<ArgumentValue> it =this.genericArgumentValues.iterator(); it.hasNext(); ) {ArgumentValue currentValue = it.next();if (newValue.getName().equals(currentValue.getName())) {it.remove();}}}this.genericArgumentValues.add(newValue);}public ArgumentValue getGenericArgumentValue(String requiredName) {for (ArgumentValue valueHolder : this.genericArgumentValues) {if (valueHolder.getName() != null && (requiredName == null || !valueHolder.getName().equals(requiredName))) {continue;}return valueHolder;}return null;}public int getArgumentCount() {return this.genericArgumentValues.size();}public boolean isEmpty() {return this.genericArgumentValues.isEmpty();}
}
  • PropertyValues类
public class PropertyValues {private final List<PropertyValue> propertyValueList;public PropertyValues() {this.propertyValueList = new ArrayList<>(0);}public List<PropertyValue> getPropertyValueList() {return this.propertyValueList;}public int size() {return this.propertyValueList.size();}public void addPropertyValue(PropertyValue pv) {this.propertyValueList.add(pv);}public void addPropertyValue(String propertyName, Object propertyValue) {addPropertyValue(new PropertyValue(propertyName, propertyValue));}public void removePropertyValue(PropertyValue pv) {this.propertyValueList.remove(pv);}public void removePropertyValue(String propertyName) {this.propertyValueList.remove(getPropertyValue(propertyName));}public PropertyValue[] getPropertyValues() {return this.propertyValueList.toArray(new PropertyValue[this.propertyValueList.size()]);}public PropertyValue getPropertyValue(String propertyName) {for (PropertyValue pv : this.propertyValueList) {if (pv.getName().equals(propertyName)) {return pv;}}return null;}public Object get(String propertyName) {PropertyValue pv = getPropertyValue(propertyName);return pv != null ? pv.getValue() : null;}public boolean contains(String propertyName) {return getPropertyValue(propertyName) != null;}public boolean isEmpty() {return this.propertyValueList.isEmpty();}
}

扩展BeanDefinition

@Data
public class BeanDefinition {String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";private boolean lazyInit = false;private String[] dependsOn;private ArgumentValues constructorArgumentValues;private PropertyValues propertyValues;private String initMethodName;private volatile Object beanClass;private String id;private String className;private String scope = SCOPE_SINGLETON;public BeanDefinition(String id, String className) {this.id = id;this.className = className;}
}

集中存放BeanDefinition

接下来,我们新增BeanDefinitionRegistry接口。它类似于一个存放BeanDefinition的仓库,可以存放、移除、获取及判断BeanDefinition对象。所以,我们初步定义四个接口对应这四个功能,分别是register、remove、get、contains。

public interface BeanDefinitionRegistry {void registerBeanDefinition(String name, BeanDefinition bd);void removeBeanDefinition(String name);BeanDefinition getBeanDefinition(String name);boolean containsBeanDefinition(String name);
}

随后调整BeanFactory,新增Singleton、Prototype的判断,获取Bean的类型。

public interface BeanFactory {Object getBean(String name) throws BeansException;boolean containsBean(String name);boolean isSingleton(String name);boolean isPrototype(String name);Class<?> getType(String name);
}

通过代码可以看到,我们让SimpleBeanFactory实现了BeanDefinitionRegistry,这样SimpleBeanFactory既是一个工厂同时也是一个仓库,你可以看下调整后的部分代码。

public class SimpleBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory, BeanDefinitionRegistry{private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);private List<String> beanDefinitionNames = new ArrayList<>();public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {this.beanDefinitionMap.put(name, beanDefinition);this.beanDefinitionNames.add(name);if (!beanDefinition.isLazyInit()) {try {getBean(name);} catch (BeansException e) {}}}public void removeBeanDefinition(String name) {this.beanDefinitionMap.remove(name);this.beanDefinitionNames.remove(name);this.removeSingleton(name);}public BeanDefinition getBeanDefinition(String name) {return this.beanDefinitionMap.get(name);}public boolean containsBeanDefinition(String name) {return this.beanDefinitionMap.containsKey(name);}public boolean isSingleton(String name) {return this.beanDefinitionMap.get(name).isSingleton();}public boolean isPrototype(String name) {return this.beanDefinitionMap.get(name).isPrototype();}public Class<?> getType(String name) {return this.beanDefinitionMap.get(name).getClass();}
}

修改完BeanFactory这个核心之后,上层对应的 ClassPathXmlApplicationContext部分作为外部集成包装也需要修改。

public class ClassPathXmlApplicationContext implements BeanFactory,
ApplicationEventPublisher{public void publishEvent(ApplicationEvent event) {}public boolean isSingleton(String name) {return false;}public boolean isPrototype(String name) {return false;}public Class<?> getType(String name) {return null;}
}

三、依赖注入

构造注入和setter注入

前面提到,注入依赖包括构造器注入,setter注入等,构造器注入主要是通过解析xml文件中的<constructor-arg>标签,setter注入则是<property>

首先先配置xml:

<?xml version="1.0" encoding="UTF-8" ?>
<beans><bean id="aservice" class="com.minis.test.AServiceImpl"><constructor-arg type="String" name="name" value="abc"/><constructor-arg type="int" name="level" value="3"/><property type="String" name="property1" value="Someone says"/><property type="String" name="property2" value="Hello World!"/></bean>
</beans>

填充属性

然后修改测试用例:

public class AServiceImpl implements AService {private String name;private int level;private String property1;private String property2;public AServiceImpl() {}public AServiceImpl(String name, int level) {this.name = name;this.level = level;System.out.println(this.name + "," + this.level);}public void sayHello() {System.out.println(this.property1 + "," + this.property2);}// 在此省略property1和property2的setter、getter方法
}

接着,简化ArgumentValues类,移除暂时未用到的方法。

public class ArgumentValues {private final List<ArgumentValue> argumentValueList = new ArrayList<>();public ArgumentValues() {}public void addArgumentValue(ArgumentValue argumentValue) {this.argumentValueList.add(argumentValue);}public ArgumentValue getIndexedArgumentValue(int index) {ArgumentValue argumentValue = this.argumentValueList.get(index);return argumentValue;}public int getArgumentCount() {return (this.argumentValueList.size());}public boolean isEmpty() {return (this.argumentValueList.isEmpty());}
}

做完准备工作之后,我们重点来看核心工作:解析 <property><constructor-arg> 两个标签。我们要在XmlBeanDefinitionReader类中处理这两个标签。

public void loadBeanDefinitions(Resource resource) {while (resource.hasNext()) {Element element = (Element) resource.next();String beanID = element.attributeValue("id");String beanClassName = element.attributeValue("class");BeanDefinition beanDefinition = new BeanDefinition(beanID,
beanClassName);//处理属性List<Element> propertyElements = element.elements("property");PropertyValues PVS = new PropertyValues();for (Element e : propertyElements) {String pType = e.attributeValue("type");String pName = e.attributeValue("name");String pValue = e.attributeValue("value");PVS.addPropertyValue(new PropertyValue(pType, pName, pValue));}beanDefinition.setPropertyValues(PVS);//处理构造器参数List<Element> constructorElements = element.elements("constructor-
arg");ArgumentValues AVS = new ArgumentValues();for (Element e : constructorElements) {String aType = e.attributeValue("type");String aName = e.attributeValue("name");String aValue = e.attributeValue("value");AVS.addArgumentValue(new ArgumentValue(aType, aName, aValue));}beanDefinition.setConstructorArgumentValues(AVS);this.simpleBeanFactory.registerBeanDefinition(beanID,
beanDefinition);}}
}

在SimpleBeanFactory类中,就可以编写核心的createBean方法(用于构造器注入和setter注入)

注:这里使用的是通用解析class,所以在beandefinition中,需要保证beandefinition的type是标准类的形式,如java.lang.String

/*** @param beanDefinition* @return Object* @doc: 根据beanDefinition创建bean* @author 17605* @date 2025/06/08*/private Object createBean(BeanDefinition beanDefinition) throws ClassNotFoundException {Class<?> clz = null;Object obj = null;Constructor<?> con = null;try {clz = Class.forName(beanDefinition.getClassName());// 处理构造器参数ArgumentValues argumentValues = beanDefinition.getConstructorArgumentValues();//如果有参数if (!argumentValues.isEmpty()) {Class<?>[] paramTypes = new Class<?>[argumentValues.getArgumentCount()];Object[] paramValues = new Object[argumentValues.getArgumentCount()];//对每一个参数,分数据类型分别处理for (int i = 0; i < argumentValues.getArgumentCount(); i++) {ArgumentValue argumentValue = argumentValues.getIndexedArgumentValue(i);// 解析类型并获取类String type = argumentValue.getType();Class<?> aClass = Class.forName(type);paramTypes[i] = aClass;// 将值转为对应的类值paramValues[i] = aClass.cast(argumentValue.getValue());}//按照特定构造器创建实例con = clz.getConstructor(paramTypes);obj = con.newInstance(paramValues);} else {//如果没有参数,直接创建实例obj = clz.newInstance();}} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException |IllegalAccessException e) {throw new RuntimeException(e);}// 处理属性PropertyValues propertyValues = beanDefinition.getPropertyValues();if (!propertyValues.isEmpty()) {for (int i = 0; i < propertyValues.size(); i++) {//对每一个属性,分数据类型分别处理PropertyValue propertyValue = propertyValues.getPropertyValueList().get(i);String pType = propertyValue.getType();String pName = propertyValue.getName();Object pValue = propertyValue.getValue();// 解析类型并获取类Class<?> paramTypes = Class.forName(pType);//按照setXxx规范查找setter方法,调用setter方法设置属性String methodName = "set" + pName.substring(0, 1).toUpperCase() + pName.substring(1);Method method = null;try {method = clz.getMethod(methodName, paramTypes);method.invoke(obj, pValue);} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {throw new RuntimeException(e);}}}return obj;}

循环依赖

bean的生命周期大致是:实例化 —> 填充属性 —> 初始化
Spring在解决循环依赖的时候是通过设立缓存,Spring使用了三级缓存,理论上二级缓存也可以解决循环依赖,由于此时我们还没有使用到代理类,所以这里我们就使用二级缓存。

将创建好的实例放在earlySingletonObjects(缓存)中,在填充属性的时候,查询是否在缓存中存在,如果存在,就注入(注:此时注入的属性是没有注入过属性的bean

按照bean的生命周期,我们就可以设置重构SimpleBeanFactory:

	private Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);private List<String> beanDefinitionNames = new ArrayList<>();private Map<String, Object> earlySingletonObjects = new HashMap<>();public Object getBean(String beanName) throws BeansException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {// 看容器中是否有Bean实例Object singleton = singletons.get(beanName);// 如果还没有这个bean的实例,则获取它的定义来创建实例if (singleton == null) {//如果没有bean,则创建bean并注册BeanDefinition beanDefinition = beanDefinitions.get(beanName);singleton = createBean(beanDefinition);this.registerSingleton(beanName, singleton);// 预留beanpostprocessor位置// step 1: postProcessBeforeInitialization// step 2: afterPropertiesSet// step 3: init-method// step 4: postProcessAfterInitialization}return singleton;}private Object createBean(BeanDefinition beanDefinition) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {Class<?> clz = null;// 如果存在缓存中,代表形成了循环依赖,返回null;if (earlySingletonObjects.get(beanDefinition.getId()) != null) {return null;}//1. 创建实例Object obj = doCreateBean(beanDefinition);//2. 存入缓存this.earlySingletonObjects.put(beanDefinition.getId(), obj);clz = Class.forName(beanDefinition.getClassName());//3. 填充属性handleProperties(beanDefinition, clz, obj);//4. 装入容器singletons.put(beanDefinition.getId(), obj);//5. 清除缓存earlySingletonObjects.remove(beanDefinition.getId());return obj;}/*** @param beanDefinition* @param clz* @param obj* @doc: 填充属性* @author 17605* @date 2025/06/09*/private void handleProperties(BeanDefinition beanDefinition, Class<?> clz, Object obj) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {// 处理属性PropertyValues propertyValues = beanDefinition.getPropertyValues();if (propertyValues != null && !propertyValues.isEmpty()) {for (int i = 0; i < propertyValues.size(); i++) {//对每一个属性,分数据类型分别处理PropertyValue propertyValue = propertyValues.getPropertyValueList().get(i);String pType = propertyValue.getType();String pName = propertyValue.getName();Object pValue = propertyValue.getValue();String ref = propertyValue.getRef();// 解析类型并获取类// 看缓存中是否存在实例Object o = earlySingletonObjects.get(ref);Method method = null;Class<?> paramTypes = ClassLoadUtil.loadClassByClassName(pType);// 存在实例,则将实例注入 或者是基本数据类型//TODO 2025/6/9// 基本数据类型if (ClassLoadUtil.isLangType(paramTypes)) {}// 存在实例else if (o != null) {pValue = o;} else {// 实例不存在缓存则创建实例pValue = createBean(beanDefinitions.get(ref));}//按照setXxx规范查找setter方法,调用setter方法设置属性String methodName = "set" + pName.substring(0, 1).toUpperCase() + pName.substring(1);// 存在实例try {method = clz.getMethod(methodName, paramTypes);method.invoke(obj, pValue);} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {throw new RuntimeException(e);}}}}/*** @param beanDefinition* @return Object* @doc: 创建实例 (调用构造参数)* @author 17605* @date 2025/06/09*/private Object doCreateBean(BeanDefinition beanDefinition) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> clz = null;Object obj = null;Constructor<?> con = null;clz = Class.forName(beanDefinition.getClassName());// 处理构造器参数ArgumentValues argumentValues = beanDefinition.getConstructorArgumentValues();//如果有参数if (argumentValues != null && !argumentValues.isEmpty()) {Class<?>[] paramTypes = new Class<?>[argumentValues.getArgumentCount()];Object[] paramValues = new Object[argumentValues.getArgumentCount()];//对每一个参数,分数据类型分别处理for (int i = 0; i < argumentValues.getArgumentCount(); i++) {ArgumentValue argumentValue = argumentValues.getIndexedArgumentValue(i);// 解析类型并获取类String type = argumentValue.getType();Object value = argumentValue.getValue();Class<?> aClass = ClassLoadUtil.loadClassByClassName(type);paramTypes[i] = aClass;// 将值转为对应的类值paramValues[i] = ClassLoadUtil.resolveValue(aClass, value);}//按照特定构造器创建实例con = clz.getConstructor(paramTypes);obj = con.newInstance(paramValues);}// 只有无参构造器else {con = clz.getConstructor();obj = con.newInstance();}return obj;}/*** @doc: 构造所有bean* @author 17605* @date 2025/06/09*/public void refresh() throws ClassNotFoundException, InvocationTargetException, BeansException, NoSuchMethodException, InstantiationException, IllegalAccessException {for (String beanName : beanDefinitionNames) {getBean(beanName);}}

四、支持注解

前面我们使用的注入方式都是xml配置注入,我们知道Spring中可以使用@Autowire注入,所以接下俩我们要使我们的容器支持该注解,然后我们就可以知道:

  1. 为什么构造器注入先于Autowire注入?
  2. 为什么Autowire注入是setter注入?(通过反射获取set方法设值)
  3. 为什么Autowire注入和构造器之间形成循环依赖是如何解决的?

先定义注解@Autowire:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

接下来,我们Bean后处理器,处理在构造器注入完成后的处理,包括注解解析。核心就是:解析被@Autowire修饰的属性,然后在IOC容器中寻找是否有这个属性的bean,然后调用该类的set方法注入。
这也就是为什么@Autowire需要需要注入的bean事先在IOC中已经创建好了

public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {private AutowireCapableBeanFactory beanFactory;@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {Object result = bean;Class<?> clazz = bean.getClass();Field[] fields = clazz.getDeclaredFields();if(fields!=null){//对每一个属性进行判断,如果带有@Autowired注解则进行处理for(Field field : fields){boolean isAutowired =
field.isAnnotationPresent(Autowired.class);if(isAutowired){//根据属性名查找同名的beanString fieldName = field.getName();Object autowiredObj =
this.getBeanFactory().getBean(fieldName);//设置属性值,完成注入try {field.setAccessible(true);field.set(bean, autowiredObj);System.out.println("autowire " + fieldName + " for bean
" + beanName);}}}}return result;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {return null;}public AutowireCapableBeanFactory getBeanFactory() {return beanFactory;}public void setBeanFactory(AutowireCapableBeanFactory beanFactory) {this.beanFactory = beanFactory;}
}

接下来我们创建一个支持注解的工厂:AutowireCapableBeanFactory

/*** @param bean* @param beanName* @return Object* @doc: 初始化前方法(注入其他需要注入的属性)* @author 17605* @date 2025/06/10*/@Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object bean, String beanName) throws BeansException {Class<?> clazz = bean.getClass();Field[] fields = clazz.getDeclaredFields();//对每一个属性进行判断,如果带有@Autowired注解则进行处理for (Field field : fields) {boolean isAutowired = field.isAnnotationPresent(Autowired.class);if (isAutowired) {//根据属性名查找同名的beanString fieldName = field.getName();
//                Object autowiredObj = this.getBean(fieldName);
//                Class<?> aClass = field.getClass();
//                // 按名称匹配失败,按类型再匹配一次
//                if (autowiredObj == null){
//                    autowiredObj = this.getBean()
//                }Class<?> fieldType = field.getType();try {// 按类型匹配Object autowiredObj = this.getBean(fieldType.getName());// 允许私有属性注入field.setAccessible(true);//TODO 2025/6/11 这里要避免重复注入if (field.get(bean) == null){field.set(bean, autowiredObj);System.out.println("autowire " + fieldName + " for bean " + beanName);}} catch (Exception e) {throw new RuntimeException(e);}}}return bean;}/*** @param existingBean* @param beanName* @return Object* @doc: 初始化后方法* @author 17605* @date 2025/06/10*/@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
//        Object result = existingBean;
//        for (BeanPostProcessor beanProcessor : this.beanPostProcessors) {
//            result = beanProcessor.postProcessAfterInitialization(result, beanName);
//            if (result == null) {
//                return result;
//            }
//        }
//        return result;return null;}
protected final Map<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);protected final List<String> beanDefinitionNames = new ArrayList<>();protected final Map<String, Object> earlySingletonObjects = new HashMap<>(16);public AbstractBeanFactory() {}public void refresh() {for (String beanName : beanDefinitionNames) {try {getBean(beanName);} catch (BeansException | ClassNotFoundException | InvocationTargetException | NoSuchMethodException |InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}}}@Overridepublic Object getBean(String beanName) throws BeansException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {//先尝试直接从容器中获取完整bean实例(按名称匹配)Object singleton = this.getSingleton(beanName);if (singleton != null) {return singleton;}// 按名称匹配定义BeanDefinition beanDefinition = beanDefinitions.get(beanName);// 按类型匹配定义if (beanDefinition == null) {for (Map.Entry<String, BeanDefinition> entry : beanDefinitions.entrySet()) {if (entry.getValue().getClassName().equals(beanName)) {beanDefinition = entry.getValue();break;}}}// 定义不存在(按名称匹配失败,或者按类型匹配失败)if (beanDefinition == null) return null;// 按类型匹配singleton = singletons.get(beanDefinition.getClassName());if (singleton != null) {return singleton;}//如果没有完整bean实例,则尝试从毛胚实例中获取构造方法创建的bean(没有填充属性)singleton = this.earlySingletonObjects.get(beanName);if (singleton == null) {//如果连毛胚都没有(没有构造方法创建的实例),则创建bean实例singleton = doCreateBean(beanDefinition);}// 填充属性this.handleProperties(beanDefinition, Class.forName(beanDefinition.getClassName()), singleton);// 加入容器中this.registerBean(beanDefinition.getClassName(), singleton);// TODO 2025/6/11 测试@Autowired和xml形成的循环依赖是否可以跑通// KEYPOINT 初始化// 进行beanpostprocessor处理// step 1: 初始化前的操作applyBeanPostProcessorsBeforeInitialization(singleton, beanName);// step 2: 初始化if (beanDefinition.getInitMethodName() != null && !beanDefinition.equals("")) {invokeInitMethod(beanDefinition, singleton);}// step 3: 初始化后的操作applyBeanPostProcessorsAfterInitialization(singleton, beanName);return singleton;}private void invokeInitMethod(BeanDefinition beanDefinition, Object obj) {Class<?> clz = beanDefinition.getClass();Method method = null;try {method = clz.getMethod(beanDefinition.getInitMethodName());method.invoke(obj);} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {throw new RuntimeException(e);}}@Overridepublic boolean containsBean(String name) {return containsSingleton(name);}public void registerBean(String beanName, Object obj) {this.registerSingleton(beanName, obj);}@Overridepublic void registerBeanDefinition(String name, BeanDefinition beanDefinition) {this.beanDefinitions.put(name, beanDefinition);this.beanDefinitionNames.add(name);// 是否在加载时创建实例// KEYPOINT 这里只是加载时  创建实例,而不是创建完整beanif (!beanDefinition.isLazyInit()) {try {Object o = doCreateBean(beanDefinition);earlySingletonObjects.put(name, o);} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException |InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}}}

到这里我们就可以知道:由于在容器中,根据名称还是根据类型注入,可以根据容器的key设置,以及获取bean的流程控制,实际spring中@Autowire是优先根据类型匹配的,这里我们设置的方案是根据名称匹配。
源码地址:https://gitee.com/daiyuling/mini-spring 持续更新中~~

相关文章:

  • 电阻、电容、电感
  • 漫画Android:从网络加载一个50MB的图片,要注意什么?
  • 探秘KingbaseES在线体验平台:技术盛宴还是虚有其表?
  • EasyExcel 4.X 读写数据
  • 『大模型笔记』第3篇:多长的 Prompt 会阻塞其他请求?优化策略解析
  • AI测试开发工程师如何用大模型调用工具:从入门到实践
  • Linux --Ext系列文件系统
  • 【PWN】04.Linux-User Mode-栈溢出-x86-中级ROP
  • 工业 AI Agent:智能化转型的核心驱动力
  • openGrok大型源码(AOSP/openHarmonyOS等)开发提升检索效率必备神器
  • Day03_数据结构
  • 微軟將開始使用 Copilot Vision 監控 Windows 10 和 11 用戶的螢幕
  • Python 装饰器
  • 136只出现一次的数字
  • C++性能测评工具
  • 【数据库】在线体验KingbaseES平台,零门槛学习,并快速体验Oracle增改查全基础功能
  • MSPM0G3507学习笔记(二) 超便捷配置led与按键
  • linux thermal framework(5)_thermal core
  • 60days challenge day34
  • Vue3+TypeScript 导入枚举(Enum)最佳实践
  • 济源市网站建设/杭州seo工作室
  • 做双语网站多少钱/专业seo优化推广
  • 全国商城网站建设/国内好的seo
  • 天津哪里有做网站的/企业seo排名哪家好
  • 网站建设太金手指六六二九/广东搜索引擎优化
  • pcb高端网站建设/湖南竞价优化专业公司