网站Logo 苏叶的belog

自定义SpringIOC

wdadwa
10
2026-02-21

SpringIOC基本使用

  1. dao 层

    public interface UserDao {
        public void addUser();
    }
    
    public class UserDaoImpl implements UserDao {
        @Override
        public void addUser() {
            System.out.println("保存用户。。。");
        }
    }
    
  2. service 层

    public interface UserService {
        public void addUser();
    }
    
    public class UserServiceImpl implements UserService {
    
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void addUser() {
            System.out.println("addUserService");
            userDao.addUser();
        }
    }
    
    
    
  3. xml 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    
    
        <bean id="userDao" class="com.normaling.springDemo.dao.impl.UserDaoImpl">
    
        </bean>
    
    
        <bean id="userService" class="com.normaling.springDemo.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao">
    
            </property>
        </bean>
    
    
    </beans>
    
    
  4. controller 层

    public class UserController {
        public static void main(String[] args) {
            //1.创建Spring的bean容器对象
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            //2。从容器中获取bean
            UserService userService = applicationContext.getBean("userService", UserService.class);
            //3.调用
            userService.addUser();
    
        }
    }
    

Spring核心功能结构

Spring 大约有 20 个模块,由 1300 多个不同的文件构成。这些模块可以分为:

  • 核心容器、AOP和设备支持、数据访问与集成、Web组件、通信报文和集成测试等,下面是Spring框架的总体架构图:

2953321-20260221202943998-1685116812.png

核心容器由 beans、core, context , expression (Spring Expression Language, SpEL)4 个模块组成。

  • spring-beans 和 spring-core 模块是 Spring 框架的核心模块,包含了控制反转 (Inversion of Control,IOC) 和依赖注入(Dependency Injection,DI)。

    BeanFactory 使用控制反转对应用程序的配置和依赖性规范与实际的应用程序代码进行了分离。BeanEactory 属于延时加载,也就是说在实例化容器对象后并不会自动实例化 Bean,只有当 Bean 被使用时,BeanFactory 才会对该 Bean 进行实例化与依赖关系的装配。

  • spring-context 模块构架于核心模块之上,扩展了 BeanFactory,为它添加了 Bean 生命周期控制、框架事件体系及资源加载透明化等功能。此外,该模块还提供了许多企业级支持,如邮件访问、远程访问、任务调度等 Applicationcontext 是该模块的核心接口, 它的超类是 BeanFactory. 与 BeanEactory 不同,ApplicationContex 实例化后会自动对所有的单实例 Bean 进行实例化与依赖关系的装配,使之处于待用状态。

  • spring-context-support 模块是对 spring Ioc 容器及 IoC 子容器的扩展支持。

  • spring-context-indexer 模块是 Spring 的类管理组件和 classpath 扫描组件。

  • spring-expression 模块是统一表达式语言 (EL) 的扩展模块,可以查询、管理运行中的对象,同时也可以方便地调用对象方法,以及操作数组、集合等。它的语法类似于传统 EL,但提供了额外的功能,最出色的要数函数调用和简单字符串的模板函数。EL 的特性是基于 Spring 产品的需求而设计的,可以非常方便地同 SpringIoc 进行交互。

Spring 的 Bean

Spring 就是面向 Bean 的编程 (BOP, Bean Oriented Programming) Bean 在 Spring 中处于核心地位。Bean 对于 Spring 的意义就像 object 对于 oop 的意义一样,Spring 中没有 Bean 也就没有 Spring 存在的意义。Spring IoC 容器通过配置文件或者注解的方式来管理 bean 对象之间的依赖关系。

spring 中 bean 用于对一个类进行封装。如下面的配置:

    <bean id="userDao" class="com.normaling.springDemo.dao.impl.UserDaoImpl">

    </bean>

为什么 Bean 如此重要呢?

  • spring 将bean对象交由一个叫Ioc容器进行管理。
  • bean对象之间的依赖关系在配置文件中体现,并由spring完成。

SpringIOC相关接口分析

BeanFactory解析

Spring 中 Bean 的创建是典型的工厂模式,这一系列的 Bean 工厂,即 IoC 容器,为开发者管理对象之间的依赖关系提供了很多便利和基础服务,在 Spring 中有许多 IoC 容器的实现供用户选择,其相互关系如下图所示。

2953321-20260221204635780-1583231730.png

其中,BeanFactory 作为最顶层的一个接口,定义了 IoC 容器的基本功能规范,BeanEactory 有三个重要的子接口:ListableBeanFactory、 HierarchicalBeanFactory 和 AutowireCapableBeanFactory. 但是从类图中可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。

那么为何要定义这么多层次的接口呢?

每个接口都有它的使用场合,主要是为了区分在 Spring 内部操作过程中对象的传递和转化,对对象的数据访问所做的限制。例如,

  • ListableBeanFactory接口表示这些Bean可列表化
  • HierarchicalBeanFactory表示这些Bean 是有继承关系的,也就是每个 Bean 可能有父 Bean
  • AutowireCapableBeanFactory 接口定义Bean的自动装配规则。

这三个接口共同定义了 Bean 的集合、Bean 之间的关系及 Bean 行为。最基本的 IoC 容器接口是 BeanFactory,来看一下它的源码

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";
    
	//根据bean的名称获取IOC容器中的的bean对象
    Object getBean(String var1) throws BeansException;
	//根据bean的名称获取IOC容器中的的bean对象,并指定获取到的bean对象的类型,这样我们使用时就不需要进行类型强转了
    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

在 BeanEactory 里只对 Ioc 容器的基本行为做了定义,根本不关心你的 Bean 是如何走义及怎样加载的。正如我们只关心能从工厂里得到什么产品,不关心工厂是怎么生产这些产品的。
BeanFactory 有一个很重要的子接口,就是ApplicationContext接口,该接口主要来规范容器中的 bean 对象是非延时加载,即在创建容器对象的时候就对象 bean 进行初始化,并存储到一个容器中。

2953321-20260221205159132-233329347.png

要知道工厂是如何产生对象的,我们需要看具体的 IoC 容器实现,Spring 提供了许多 IoC 容器实现,比如:

  • ClasspathXmlApplicationContext::跟据类路径加载xml配置文件,并创建IOC容器对象。
  • FileSystemxmlApplicationcontext:根据系统路径加载xml配置文件,并创建IOC容器对象。
  • AnnotationconfigApplicationContext:加载注解类配置,并创建Ioc容器。

BeanDefinition解析

Spring IoC 容器管理我们定义的各种 Bean 对象及其相互关系,而 Bean 对象在 Spring 实现中是以BeanDefinition来描述的,如下面配置文件

<bean id="userDao" class="com.normaling.springDemo.dao.impl.UserDaoImpl">

    </bean>

继承体系如下

2953321-20260221205447578-1224133317.png

BeanDefinitionReader解析

Bean 的解析过程非常复杂,功能被分得很细,因为这里需要被扩展的地方很多,必须保证足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 spring 配置文件的解析。这个解析过程主要通过BeanDefinitionReader来完成,看看 Spring 中 BeanDefinitionReader 的类结构图,如下图所示。

2953321-20260221205721857-1365737907.png

看看 BeanDefinitionReader 接口定义的功能来理解它具体的作用:

package org.springframework.beans.factory.support;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;

public interface BeanDefinitionReader {
    // 获取beanRegistry
    BeanDefinitionRegistry getRegistry();

    @Nullable
    ResourceLoader getResourceLoader();

    @Nullable
    ClassLoader getBeanClassLoader();

    BeanNameGenerator getBeanNameGenerator();
	// 下面的loadBeanDefinitions都是加载bean定义,从指定的资源中
    int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;
    int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}

BeanDefinitionRegistry解析

BeanDefinitionReader 用来解析 bean 定义,并封装 BeanDefinition 对象,而我们定义的配置文件中定义了很多 bean 标签,所以就有一个问题,解析的 BeanDefinition 对象存储到哪儿?答案就是 BeanDefinition 的注册中心,而该注册中心页层接口就是BeanDefinitionRegistry

package org.springframework.beans.factory.support;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.AliasRegistry;

public interface BeanDefinitionRegistry extends AliasRegistry {
    //往注册表中注册bean
    void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;
    //从注册表中删除指定名称的bean
    void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
	//获取注册表中指定名称的bean
    BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
	//判断注册表中是否已经注册了指定名称的bean
    boolean containsBeanDefinition(String var1);
	//获取注册表中所有的bean的名称
    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String var1);
}

其继承体系如下

2953321-20260221210152791-1917980760.png

从上面类图可以看到 BeanDefinitionRegistry 接口的子实现类主要有以下几个:

  • DefaultListableBeanFactory 在该类中定义了如下代码,就是用来注册 bean

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
    
  • SimpleBeanDefinitionRegistry

    在该类中定义了如下代码,就是用来注册 bean

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(64);
    

创建容器

ClassPathXmlApplicationcontext 对 Bean 配置资源的载入是从 refresh ()方法开始的。refresh () 方法是一个模板方法,规定了 IoC 容器的启动流程,有些逻辑要交给其子类实现。它对 Bean 配置资源进行载入,ClassPathxmlApplicationContext 通过调用其父类 AbstractApplicationcontext 的 refresh () 方启动整个 IoC 容器对 Bean 定义的载入过程。

自定义SpringIOC

现要对下面的配置文件进行解析,并自定义 Spring 框架的 IOC 对涉及到的对象进行管理。

<?xml version='1.0' encoding="UTF-8"?>
<beans>
    
	<bean id="userDao" class="com.normaling.springDemo.dao.impl.UserDaoImpl">
    </bean>
    
    <bean id="userService" class="com.normaling.springDemo.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao">
        </property>
    </bean>
    
</beans>

定义bean相关pojo类

PropertyValue类

用于封装 bean 的属性,体现到上面的配置文件就是封装 bean 标签的子标签 property 标签数据。

package com.normaling.deffiniSpringIoc.pojo;
/**
 * 用来封装bean标签下的property标签的属性
 * name属性
 * ref属性
 * value属性: 给基本数据类型及string类型数据赋的值
 */
public class PropertyValue {
    private String name;
    private String ref;
    private String value;

    public PropertyValue(String name, String ref, String value) {
        this.name = name;
        this.ref = ref;
        this.value = value;
    }

    public PropertyValue() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRef() {
        return ref;
    }

    public void setRef(String ref) {
        this.ref = ref;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

MutablePropertyValue类

一个 bean 标签可以有多个 property 子标签,所以再定义一个 MutablePropertyValues 类,用来存储并管理多个 PropertyValue 对象.

package com.normaling.deffiniSpringIoc.pojo;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class MutablePropertyValues implements Iterable<PropertyValue> {


    //定义list集合对象,用来存储PropertyValue对象
    private List<PropertyValue> propertyValues;

    public MutablePropertyValues(List<PropertyValue> propertyValues) {
        if(propertyValues == null){
            this.propertyValues = new ArrayList<PropertyValue>();
        }else{
            this.propertyValues = propertyValues;
        }
    }

    public MutablePropertyValues() {
        this.propertyValues = new ArrayList<PropertyValue>();
    }

    //获取迭代器对象
    public Iterator<PropertyValue> iterator() {
        return propertyValues.iterator();
    }

    //获取所有的propertyValues对象,返回以数组的形式
    public PropertyValue[] getPropertyValues() {
        // 将集合转换为数组并返回
        return propertyValues.toArray(new PropertyValue[0]);
    }
    //根据name属性值获取PropertyValue对象
    public PropertyValue getPropertyValue(String propertyName) {
        for (PropertyValue propertyValue : propertyValues) {
            if(propertyValue.getName().equals(propertyName)){
                return propertyValue;
            }
        }
        return null;
    }
    // 判断集合是否为空
    public boolean isEmpty() {
        return propertyValues.isEmpty();
    }
    public MutablePropertyValues addPropertyValue(PropertyValue propertyValue) {
        // 判断集合是否为空,若为空则直接添加
        if (propertyValues.isEmpty()) {
            propertyValues.add(propertyValue);
            return this;
        }

        // 遍历现有属性,查找是否有同名属性
        for (int i = 0; i < propertyValues.size(); i++) {
            PropertyValue currentValue = propertyValues.get(i);
            if (currentValue.getName().equals(propertyValue.getName())) {
                // 找到同名属性,直接覆盖
                propertyValues.set(i, propertyValue);
                return this;
            }
        }

        // 没有找到同名属性,直接添加
        propertyValues.add(propertyValue);
        return this;
    }
    // 判断是否含有指定name的对象
    public boolean contains(String propertyName) {
        return this.getPropertyValue(propertyName) != null;
    }

}

BeanDefinition类

BeanDefinition 类用来封装 bean 信息的,主要包含 id (即 bean 对象的名称)、class( 需要交由 spring 管理的类的全
类名 ) 及子标签 property 数据。

package com.normaling.deffiniSpringIoc.pojo;

public class BeanDefinition {
    private String id;
    private String className;
    private MutablePropertyValues propertyValues;

    public BeanDefinition() {
        this.propertyValues = new MutablePropertyValues();
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public MutablePropertyValues getPropertyValues() {
        return propertyValues;
    }

    public void setPropertyValues(MutablePropertyValues propertyValues) {
        this.propertyValues = propertyValues;
    }
}

定义注册表相关类

BeanDefinitionRegistry接口

BeanDefinitionRegistry 接口定义了注册表的相关操作,定义如下功能:

  • 注册BeanDefinition对象到注册表中
  • 从注册表中删除指定名称的BeanDefinition对象
  • 根据名称从注册表中获取BeanDefinition对象
  • 判断注册表中是否包含指定名称的BeanDefinition对象
  • 获取注册表中BeanDefinition对象的个数
  • 获取注册表中所有的BeanDefinition的名称
package com.normaling.deffiniSpringIoc.DefinitionRegistry;

import com.normaling.deffiniSpringIoc.pojo.BeanDefinition;

public interface BeanDefinitionRegistry {

    // 注册BeanDefinition对象到注册表中
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    // 从注册表中删除指定名称的BeanDefinition
    void removeBeanDefinition(String beanName);

    // 根据名称从注册表中获取BeanDefinition对象
    BeanDefinition getBeanDefinition(String beanName) throws Exception;

    // 判断注册表中是否包含指定名称的bean
    boolean containsBeanDefinition(String beanName);

    // 获取注册表中bean的数量
    int getBeanDefinitionCount();

    // 获取所有的bean的name
    String[] getBeanDefinitionNames();
}

SimpleBeanDefinitionRegistry类

该类实现了 BeanDefinitionRegistry 接口,定义了 Map 集合作为注册表容器。

package com.normaling.deffiniSpringIoc.DefinitionRegistry;

import com.normaling.deffiniSpringIoc.pojo.BeanDefinition;
import java.util.HashMap;
import java.util.Map;

public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry{

    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName,beanDefinition);
    }

    @Override
    public void removeBeanDefinition(String beanName) {
        beanDefinitionMap.remove(beanName);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws Exception {
        return beanDefinitionMap.get(beanName);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return beanDefinitionMap.keySet().toArray(new String[0]);
    }
}

定义解析器相关类

BeanDefinitionReader接口

BeanDefinitionReader 是用来解析配置文件并在注册表中注册 bean 的信息。定义了两个规范:

  • 获取注册表的功能,让外界可以通过该对象获取注册表对象。
  • 加载配置文件,并注册bean数据。
public interface BeanDefinitionReader {
    // 获取注册表
    BeanDefinitionRegistry getRegistry();
    // 加载配置文件,并注册bean数据
    void loadBeanDefinitions(String location) throws Exception;
}

XmlBeanDefinitionReader类

XmlBeanDefinitionReader 类是专门用来解析 xml 配置文件的。该类实现 BeanDefinitionReader 接口并实现接口中的两个功能。

package com.normaling.deffiniSpringIoc.DefinitionReader;

import com.normaling.deffiniSpringIoc.DefinitionRegistry.BeanDefinitionRegistry;
import com.normaling.deffiniSpringIoc.DefinitionRegistry.SimpleBeanDefinitionRegistry;
import com.normaling.deffiniSpringIoc.pojo.BeanDefinition;
import com.normaling.deffiniSpringIoc.pojo.MutablePropertyValues;
import com.normaling.deffiniSpringIoc.pojo.PropertyValue;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;


public class XmlBeanDefinitionReader implements BeanDefinitionReader{

    private BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader() {
        this.registry = new SimpleBeanDefinitionRegistry();
    }

    @Override
    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    @Override
    public void loadBeanDefinitions(String location) throws Exception {
        //使用dom4j解析xml配置文件
        SAXReader reader = new SAXReader();
        InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(location);
        Document document = reader.read(is);
        // 根据document对象获取根标签对象 <beans>
        Element rootElement = document.getRootElement();
        // 获取根标签下面的所有bean标签对象
        List<Element> elements = rootElement.elements("bean");
        for (Element element : elements) {
            // 获取id
            String id = element.attributeValue("id");
            // 获取class
            String clazz = element.attributeValue("class");
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setId(id);
            beanDefinition.setClassName(clazz);
            // 创建 MutablePropertyValues对象
            MutablePropertyValues propertyValues = new MutablePropertyValues();
            // 获取bean标签下面所有的property对象
            List<Element> propertyElements = element.elements("property");
            for (Element propertyElement : propertyElements) {
                // 获取name
                String name = propertyElement.attributeValue("name");
                // 获取value
                String value = propertyElement.attributeValue("value");
                // 获取ref
                String ref = propertyElement.attributeValue("ref");
                PropertyValue propertyValue = new PropertyValue(name, value, ref);
                propertyValues.addPropertyValue(propertyValue);
            }
            beanDefinition.setPropertyValues(propertyValues);
            // 将 beanDefinition注册
            registry.registerBeanDefinition(id, beanDefinition);
        }

    }
}

IOC容器相关类

BeanFactory接口

在该接口中定义 IOC 容器的统一规范即获取 bean 对象。

package com.normaling.deffiniSpringIoc.ioc;

public interface BeanFactory {

    // 根据bean对象的名称获取对象
    public Object getBean(String beanName) throws Exception;
    // 根据bean对象的名称获取对象,并进行类型转换
    public <T> T getBean(String beanName, Class<T> clazz) throws Exception;
}

ApplicationContext接口

该接口的所以的子实现类对 bean 对象的创建都是非延时的,所以在该接口中定义 refresh() 方法,该方法主要完成以下两个功能:

  • 加载配置文件。
  • 根据注册表中的BeanDefinition对象封装的数据进行bean对象的创建。
package com.normaling.deffiniSpringIoc.ioc;


public interface ApplicationContext extends BeanFactory{
    // 加载配置文件并进行对象创建
    public void refresh() throws Exception;
}

AbstractApplicationContext类

作为 ApplicationContext 接口的子类,所以该类也是非延时加载,所以需要在该类中定义一个 Map 集合,作为 bean 对象存储的容器

声明 BeanDefinitionReader 类型的变量,用来进行 xml 配置文件的解析,符合单一职责原则。

BeanDefinitionReader 类型的对象创建交由子类实现,因为只有子类明确到底创建 BeanDefinitionReader 哪儿个子实现类对象。

package com.normaling.deffiniSpringIoc.ioc;

import com.normaling.deffiniSpringIoc.DefinitionReader.BeanDefinitionReader;
import com.normaling.deffiniSpringIoc.DefinitionRegistry.BeanDefinitionRegistry;
import java.util.HashMap;
import java.util.Map;

public abstract class AbstractApplicationContext implements ApplicationContext{

    protected BeanDefinitionReader beanDefinitionReader;
    // 存储bean对象容器,key是id,value是bean对象
    protected Map<String,Object> singletonObjects = new HashMap<>();
    // 配置文件的地址
    protected String configLocation;

    public void refresh() throws Exception {
        // 加载beanDefinition
        beanDefinitionReader.loadBeanDefinitions(configLocation);
        // 初始化bean
        finishBeanInitialization();
    }

    private void finishBeanInitialization() throws Exception {
        // 获取注册表对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

        // 获取beanDefinition集合
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            // 进行bean初始化
            getBean(beanDefinitionName);
        }

    }
}

ClassPathXmlApplicationContext类

该类主要是加载类路径下的配置文件,并进行 bean 对象的创建,主要完成以下功能:

  • 在构造方法中,创建BeanDefinitionReader对象。
  • 在构造方法中,调用refresh()方法,用于进行配置文件加载、创建bean对象并存储到容器中。
  • 重写父接口中的getBean()方法,并实现依赖注入操作。
package com.normaling.deffiniSpringIoc.ioc;

import com.normaling.deffiniSpringIoc.DefinitionReader.BeanDefinitionReader;
import com.normaling.deffiniSpringIoc.DefinitionReader.XmlBeanDefinitionReader;
import com.normaling.deffiniSpringIoc.DefinitionRegistry.BeanDefinitionRegistry;
import com.normaling.deffiniSpringIoc.pojo.BeanDefinition;
import com.normaling.deffiniSpringIoc.pojo.MutablePropertyValues;
import com.normaling.deffiniSpringIoc.pojo.PropertyValue;

import java.lang.reflect.Method;


public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        // 构建解析器对象
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try{
            refresh();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String beanName) throws Exception {
        // 判断对象容器中是否包含指定名称的bean对象,如果包含,直接返回即可,如果不包含,需要自行创建
        Object obj = singletonObjects.get(beanName);
        if(obj != null){
            return obj;
        }
        // 获取注册表对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        // 获取beanDefinition对象
        BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
        // 获取bean信息里面的className
        String className = beanDefinition.getClassName();
        // 反射构建对象
        Class<?> clazz = Class.forName(className);
        obj = clazz.newInstance();
        // 进行依赖注入操作,因为bean对象里面可能依赖了其他的bean
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            String name = propertyValue.getName();
            String ref = propertyValue.getRef();
            String value = propertyValue.getValue();
            // ref就是引用数据类型
            if(ref != null && !ref.isEmpty()){
                // 获取依赖的bean对象
                Object bean = getBean(ref);
                // 拼接方法名
                String methodName = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
                Method[] methods = obj.getClass().getMethods();
                for (Method method : methods) {
                    if(method.getName().equals(methodName)){
                        method.invoke(obj, bean);
                    }
                }
            }
            // value就是基本数据类型
            if(value != null && !value.isEmpty()){
                // 拼接方法名
                String methodName = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
                // 获取所有方法对象,demo只写String类型
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(obj, value);
            }
        }


        singletonObjects.put(beanName, obj);

        return obj;
    }

    @Override
    public <T> T getBean(String beanName, Class<T> clazz) throws Exception {
        Object bean = getBean(beanName);
        if(bean != null){
            return clazz.cast(bean);
        }
        return null;
    }
}

测试

import com.normaling.deffiniSpringIoc.ioc.ClassPathXmlApplicationContext;
import com.normaling.springDemo.service.UserService;


public class UserController {
    public static void main(String[] args) throws Exception {
        //1.创建Spring的bean容器对象
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2。从容器中获取bean
        UserService userService = applicationContext.getBean("userService", UserService.class);

        //3.调用
        userService.addUser();

    }
}
动物装饰