手写一个Spring:一、IOC容器

发布于:2025-06-18 ⋅ 阅读:(13) ⋅ 点赞:(0)

前置
首先先引入依赖:

    <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 {
    // 保存BeanDefinition
    private List<BeanDefinition> beanDefinitions = new ArrayList<>();
    // ioc容器,存储bean
    private 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的定义存放到beanDefinitions
                beanDefinitions.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实例的map
    protected 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;

    @Override
    public 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){
                    //根据属性名查找同名的bean
                    String 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;
    }
    @Override
    public 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
     */
    @Override
    public 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) {
                //根据属性名查找同名的bean
                String 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
     */
    @Override
    public 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);
            }
        }
    }

    @Override
    public 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);
        }
    }

    @Override
    public boolean containsBean(String name) {
        return containsSingleton(name);
    }

    public void registerBean(String beanName, Object obj) {
        this.registerSingleton(beanName, obj);
    }

    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        this.beanDefinitions.put(name, beanDefinition);
        this.beanDefinitionNames.add(name);
        // 是否在加载时创建实例
        // KEYPOINT 这里只是加载时  创建实例,而不是创建完整bean
        if (!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 持续更新中~~


网站公告

今日签到

点亮在社区的每一天
去签到