Spring IOC 剖析

模拟实现 Spring Ioc 控制反转功能

使用 => 原理 => 源码 => 模拟实现

使用:了解
原理:熟悉
源码 And 模拟实现: 精通

  1. 对照 Spring 功能点
  2. Spring 功能点原理
  3. Spring 功能点源码
  4. 模拟实现功能点核心逻辑

开发环境:

 Spring: 4.3.12.RELEASE
 JDK: 1.8

一、对照 Spring 功能点

Maven pom.xml 文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.galsang</groupId>
    <artifactId>SpringDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringDemo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <maven_compiler_plugin>3.5.1</maven_compiler_plugin>
        <jdk.version>1.8</jdk.version>
        <spring.version>4.3.12.RELEASE</spring.version>

        <junit.vsersion>4.12</junit.vsersion>
        <lombok.version>1.16.18</lombok.version>
    </properties>

    <dependencies>
        <!-- junit start -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.vsersion}</version>
            <scope>test</scope>
        </dependency>
        <!-- junit end -->

        <!-- lombok start -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <!-- lombok end -->

        <!-- spring start -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- spring end -->

    </dependencies>

    <build>
        <finalName>SpringDemo</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven_compiler_plugin}</version>
                    <configuration>
                        <source>${jdk.version}</source>
                        <target>${jdk.version}</target>
                        <encoding>${maven.compiler.encoding}</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

创建 Student 类 和 Test 类

Student 类


package org.galsang.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Description: 学生Bean对象
 * <br /> Author: vimx86
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

}

Test 类


package org.galsang.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.java.Log;

/**
 * Description: 测试注入
 * <br /> Author: vimx86
 */
@Log
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Test {

    private Student student;

    public void print() {
        log.info("student: ==== " + student);
    }

}

applicationContext.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 name="student" class="org.galsang.bean.Student">
        <property name="name" value="万年中华好学生"></property>
        <property name="age" value="10000"></property>
    </bean>

    <bean name="test" class="org.galsang.bean.Test" scope="prototype">
        <property name="student" ref="student"></property>
    </bean>

</beans>

App主程序


package org.galsang;

import lombok.extern.java.Log;
import org.galsang.bean.Student;
import org.galsang.bean.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Description: 主程序
 * <br /> Author: vimx86
 */
@Log
public class App {


    public static void main(String[] args) {

        // 1、Main方法入口
        // 2、BeanFactory - ClassPathXmlApplicationContext
        // 3、加载配置文件 classpath:applicationContext.xml
        // 4、根据配置文件中相关标签的定义,解析 Bean,并创建 Bean
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

        // 查看 用户定义的 Bean 对象名称
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (int i = 0; i < beanDefinitionNames.length; i++) {
            log.info(i + " == " + beanDefinitionNames[i]);
        }

        // 由容器负责管理的对象
        Test test = applicationContext.getBean("test", Test.class);
        test.print();

        // new 的新对象,容器不负责管理。。。没有进行属性 student 的注入
        new Test().print();


        // 多例
        Test testA = applicationContext.getBean("test", Test.class);
        Test testB = applicationContext.getBean("test", Test.class);
        log.info("testA == testB: === " + (testA == testB)); // false

        log.info("testA.getStudent() == testB.getStudent(): === " + (testA.getStudent() == testB.getStudent())); // true

        // 单例
        Student studentA = applicationContext.getBean("student", Student.class);
        Student studentB = applicationContext.getBean("student", Student.class);
        log.info("studentA == studentB: === " + (studentA == studentB)); // true


    }

}

运行主程序App


十一月 23, 2017 10:11:41 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@685f4c2e: startup date [Thu Nov 23 10:11:41 CST 2017]; root of context hierarchy
十一月 23, 2017 10:11:41 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
十一月 23, 2017 10:11:42 上午 org.galsang.App main
信息: 0 == student
十一月 23, 2017 10:11:42 上午 org.galsang.App main
信息: 1 == test
十一月 23, 2017 10:11:42 上午 org.galsang.bean.Test print
信息: student: ==== Student(name=万年中华好学生, age=10000)
十一月 23, 2017 10:11:42 上午 org.galsang.bean.Test print
信息: student: ==== null
十一月 23, 2017 10:11:42 上午 org.galsang.App main
信息: testA == testB: === false
十一月 23, 2017 10:11:42 上午 org.galsang.App main
信息: testA.getStudent() == testB.getStudent(): === true
十一月 23, 2017 10:11:42 上午 org.galsang.App main
信息: studentA == studentB: === true

二、Spring 功能点原理

The Spring Container 实质上就是一个超级大工厂,在系统启动时,工厂通过读取配置元数据(Configuration Metadata)进行初始化相应的(Your Business Objects(POJOS))供使用(Fully configured system Ready for Use)。

这里写图片描述

Spring IOC 功能时序图

Spring IOC 功能时序图


三、Spring 功能点源码

初始化工厂

ClassPathXmlApplicationContext


    /**
     * Create a new ClassPathXmlApplicationContext, loading the definitions
     * from the given XML file and automatically refreshing the context.
     * @param configLocation resource location
     * @throws BeansException if context creation failed
     */
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    /**
     * Create a new ClassPathXmlApplicationContext with the given parent,
     * loading the definitions from the given XML files.
     * @param configLocations array of resource locations
     * @param refresh whether to automatically refresh the context,
     * loading all bean definitions and creating all singletons.
     * Alternatively, call refresh manually after further configuring the context.
     * @param parent the parent context
     * @throws BeansException if context creation failed
     * @see #refresh()
     */
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }


AbstractApplicationContext


@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

    /**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     */
    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }

DefaultListableBeanFactory

beanDefinitionMap 用于初始化保存bean的定义。


    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

四、模拟实现功能点核心逻辑

模拟实现 Spring IOC 核心逻辑时序图

模拟实现 Spring IOC 核心逻辑时序图

Maven pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.galsang</groupId>
    <artifactId>MySpringImplIoc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>MySpringImplIoc</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <maven_compiler_plugin>3.5.1</maven_compiler_plugin>
        <jdk.version>1.8</jdk.version>

        <junit.vsersion>4.12</junit.vsersion>
        <lombok.version>1.16.18</lombok.version>
        <dom4j.version>1.6.1</dom4j.version>

    </properties>

    <dependencies>
        <!-- junit start -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.vsersion}</version>
            <scope>test</scope>
        </dependency>
        <!-- junit end -->

        <!-- lombok start -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <!-- lombok end -->

        <!-- dom4j start -->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>${dom4j.version}</version>
        </dependency>
        <!-- dom4j end -->

        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.2.0-atlassian-2</version>
        </dependency>

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>MySpringImplIoc</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven_compiler_plugin}</version>
                    <configuration>
                        <source>${jdk.version}</source>
                        <target>${jdk.version}</target>
                        <encoding>${maven.compiler.encoding}</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

创建 BeanDefinition 和 PropertyValue


package org.galsang.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

/**
 * Description: Bean 定义
 * <br /> Author: vimx86
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanDefinition {

    /**
     * Bean 的id
     */
    private String id;

    /**
     * Bean 的名称
     */
    private String name;

    /**
     * Bean 对应的类的全名
     */
    private String className;

    /**
     * Bean 的模式默认为单例
     */
    private String scope = "singleton";

    /**
     * Bean 的属性标签
     */
    private List<PropertyValue> properties = new ArrayList<>();

}

package org.galsang.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Description: Bean 的属性标签的定义
 * <br /> Author: vimx86
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PropertyValue {

    /**
     * 属性名称
     */
    private String name;

    /**
     * 属性值
     */
    private String value;

    /**
     * 引用值
     */
    private String ref;

}

创建 BeansException


package org.galsang.bean;

/**
 * Description:BeansException
 * <br /> Author: vimx86
 */
public class BeansException extends RuntimeException {
    public BeansException(String message) {
        super(message);
    }
}

创建 BeanFactory 接口定义


package org.galsang.bean;

/**
 * Description: Bean 工厂的的接口定义
 * <br /> Author: vimx86
 */
public interface BeanFactory {

    /**
     * 通过Bean的名称获取该 Bean 的实例对象
     *
     * @param beanName Bean 的名称
     * @return Bean 的实例对象
     */
    Object getBean(String name) throws BeansException;

    /**
     * @param name
     * @param requiredType
     * @param <T>
     * @return
     * @throws BeansException
     */
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

}

DefaultListableBeanFactory

创建 DefaultListableBeanFactory 实现 BeanFactory


package org.galsang.bean;

import lombok.extern.java.Log;
import org.apache.commons.beanutils.BeanUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Description:
 * <br /> Author: vimx86
 */
@Log
public class DefaultListableBeanFactory implements BeanFactory {

    public static final String SCOPE_SINGLETON = "singleton";

    /**
     * Map of bean definition objects, keyed by bean name
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    /**
     * Cache of singleton objects: bean name --> bean instance
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /**
     * 配置 元数据文件地址
     */
    private String configLocation;

    /**
     * 构造方法
     *
     * @param configLocation
     */
    protected DefaultListableBeanFactory(String configLocation) {
        this.configLocation = configLocation;
        this.loadBeanDefinitions();
        this.iniBeanFacoty();
    }

    /**
     * @param name
     * @return
     * @throws BeansException
     */
    @Override
    public Object getBean(final String name) throws BeansException {

        // 单例
        Object bean = singletonObjects.get(name);
        if (bean != null) {
            return bean;
        }

        // 多例
        return createBean(beanDefinitionMap.get(name));
    }

    /**
     * @param name
     * @param requiredType
     * @param <T>
     * @return
     * @throws BeansException
     */
    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return requiredType.cast(this.getBean(name));
    }

    /**
     * @param beanName
     * @param beanDefinition
     */
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        if (null == beanName || null == beanDefinition) {
            return;
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

    /**
     * @param beanName
     * @param singletonObject
     */
    private void registerSingletonObject(String beanName, Object singletonObject) {
        if (null == beanName || null == singletonObject) {
            return;
        }
        this.singletonObjects.put(beanName, singletonObject);
    }

    /**
     * @return
     */
    public int getBeanDefinitionCount() {
        return this.beanDefinitionMap.size();
    }

    /**
     * @return
     */
    public Map<String, BeanDefinition> getBeanDefinitionMap() {
        return beanDefinitionMap;
    }

    /**
     * 初始化 bean 工厂
     *
     * @throws BeansException
     */
    private void iniBeanFacoty() throws BeansException {
        beanDefinitionMap.forEach((k, v) -> {
            log.info("初始化 bean 工厂");

            if (SCOPE_SINGLETON.equals(v.getScope())) {
                createBean(v);
            }
        });
    }

    /**
     * 创建 Bean
     *
     * @param beanDefinition
     * @return Bean 对象
     * @throws BeansException
     */
    private Object createBean(BeanDefinition beanDefinition) throws BeansException {

        log.info(" 创建 beanDefinition " + beanDefinition);

        // 创建该类对象
        Class clazz = null;
        try {
            String className = beanDefinition.getClassName();
            log.info("className === " + className);
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("没有找到该类" + beanDefinition.getClassName());
        }

        Object beanObj = null;
        try {
            beanObj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("没有提供无参构造器");
        }

        // 获得 bean 的属性,将其注入,注入分两种情况
        // 1、value 普通属性
        // 2、ref Bean 属性
        if (beanDefinition.getProperties() != null) {
            for (PropertyValue prop : beanDefinition.getProperties()) {

                String name = prop.getName();
                String value = prop.getValue();
                String ref = prop.getRef();

                // 使用 BeanUtils 工具类完成属性注入,可以自动完成类型转换
                // 1、value 普通属性
                if (value != null) {
                    Map<String, String[]> parmMap = new HashMap<>();
                    parmMap.put(name, new String[]{value});
                    try {
                        BeanUtils.populate(beanObj, parmMap);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException("请检查你的" + name + "属性");
                    }
                }

                // 2、ref Bean 属性
                if (ref != null) {

                    // 看一看当前IOC容器中是否已存在该bean,有的话直接设置没有的话使用递归,创建该bean对象
                    Object refBean = singletonObjects.get(ref);

                    if (refBean == null) {

                        BeanDefinition refBeanDefinition = beanDefinitionMap.get(ref);

                        if (refBeanDefinition == null) {
                            throw new RuntimeException("没有找到 Bean " + ref + " 的定义");
                        }

                        // 递归的创建一个bean
                        refBean = createBean(refBeanDefinition);
                    }
                    try {
                        BeanUtils.setProperty(beanObj, name, refBean);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException("您的bean的属性" + name + "没有对应的set方法");
                    }

                }

            }
        }

        // 当 scope="singleton" 时才放置到 singletonObjects 容器中
        if (SCOPE_SINGLETON.equals(beanDefinition.getScope())) {
            registerSingletonObject(beanDefinition.getName(), beanObj);
        }

        return beanObj;

    }

    /**
     * 解析 配置元数据
     */
    private void loadBeanDefinitions() {
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(configLocation);
        xmlBeanDefinitionReader.loadBeanDefinitions(this);
    }

}

创建 XmlBeanDefinitionReader


package org.galsang.bean;

import lombok.extern.java.Log;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

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

/**
 * Description: 解析 配置元数据 文件
 * <br /> Author: vimx86
 */
@Log
public class XmlBeanDefinitionReader {

    private final String configPath;

    public XmlBeanDefinitionReader(String configPath) {
        this.configPath = configPath;
    }

    public void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {

        log.info("XmlBeanDefinitionReader ==== loadBeanDefinitions ");

        // 1.创建解析器
        SAXReader reader = new SAXReader();
        // 2.加载配置文件,得到document对象
        InputStream is = this.getClass().getResourceAsStream(configPath);
        Document doc = null;
        try {
            doc = reader.read(is);
        } catch (DocumentException e) {
            e.printStackTrace();
            throw new RuntimeException("请检查您的xml配置是否正确");
        }
        // 3.定义xpath表达式,取出所有Bean元素
        String xpath = "//bean";

        // 4.对Bean元素继续遍历
        List<Element> list = doc.selectNodes(xpath);
        if (list != null) {
            // 4.1将Bean元素的name/class属性封装到 BeanDefinition 类属性中
            for (Element bean : list) {
                BeanDefinition beanDefinition = new BeanDefinition();
                String name = bean.attributeValue("name");
                String clazz = bean.attributeValue("class");
                String scope = bean.attributeValue("scope");

                beanDefinition.setName(name);
                beanDefinition.setClassName(clazz);
                if (scope != null) {
                    beanDefinition.setScope(scope);
                }
                // 4.2获得bean下的所有property子元素
                List<Element> children = bean.elements("property");

                // 4.3将属性name/value/ref分装到类Property类中
                if (children != null) {
                    for (Element child : children) {
                        PropertyValue propertyValue = new PropertyValue();
                        String pName = child.attributeValue("name");
                        String pValue = child.attributeValue("value");
                        String pRef = child.attributeValue("ref");
                        propertyValue.setName(pName);
                        propertyValue.setRef(pRef);
                        propertyValue.setValue(pValue);
                        // 5.将property对象封装到 BeanDefinition 对象中
                        beanDefinition.getProperties().add(propertyValue);
                    }
                }
                //6.将Bean 对象注册到 beanFactory
                beanFactory.registerBeanDefinition(name, beanDefinition);
            }
        }

        // 用于观察
        int count = beanFactory.getBeanDefinitionCount();
        log.info("count === " + count);
        beanFactory.getBeanDefinitionMap().forEach((k, v) -> log.info("beanName: " + k + " == " + v));

    }


}

创建 ClassPathXmlApplicationContext


package org.galsang.bean;

/**
 * Description: BeanFactory 的一种实现方式
 * <br /> Author: vimx86
 */
public class ClassPathXmlApplicationContext extends DefaultListableBeanFactory {

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        super(configLocation);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return super.getBean(name);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return super.getBean(name, requiredType);
    }
}

创建 Car 类 和 Wheel 类


package org.galsang.bean.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.java.Log;

/**
 * Description: 测试注入
 * <br /> Author: vimx86
 */
@Log
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car {

    /**
     * 车名
     */
    private String name;

    /**
     * 车轮
     */
    private Wheel wheel;

}


package org.galsang.bean.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Description: 车轮
 * <br /> Author: vimx86
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Wheel {

    /**
     * 车轮名称
     */
    private String name;

}

applicationContext.xml


<?xml version="1.0" encoding="utf-8"?>
<beans>
    <bean name="car" class="org.galsang.bean.test.Car">
        <property name="name" value="小轿车"></property>
        <property name="wheel" ref="wheel"></property>
    </bean>

    <bean name="wheel" class="org.galsang.bean.test.Wheel" scope = "prototype">
        <property name="name" value="四轮驱动"></property>
    </bean>
</beans>

验证功能实现


package org.galsang.bean;

import lombok.extern.java.Log;
import org.galsang.bean.test.Car;
import org.galsang.bean.test.Wheel;

/**
 * Description: 测试
 * <br /> Author: vimx86
 */
@Log
public class App {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");

//        Wheel wheel = (Wheel) applicationContext.getBean("wheel");

//        Wheel wheel = applicationContext.getBean("wheel", Wheel.class);
//
//        wheel.setName("sssss");
//        log.info("wheel == " + wheel);

        /************************* === 单例 Start ===  *****************************/
        // 单例
        Car carA = applicationContext.getBean("car", Car.class);
        Car carB = applicationContext.getBean("car", Car.class);

        log.info("(carA == carB) == " + (carA == carB)); //true

        // 原因参见: Spring 单例 多例相互注入部分
        log.info("(carA.getWheel() == carB.getWheel()) == " + (carA.getWheel() == carB.getWheel())); //true
        /************************* === 单例 End ===  *****************************/


        /************************* === 多例 Start ===  *****************************/

        // 多例
        Wheel wheelA = applicationContext.getBean("wheel", Wheel.class);
        Wheel wheelB = applicationContext.getBean("wheel", Wheel.class);

        log.info("(wheelA == wheelB) == " + (wheelA == wheelB)); //false
        /************************* === 多例 End ===  *****************************/


    }

}
原文地址:https://www.cnblogs.com/ljmatlight/p/9060784.html