zoukankan      html  css  js  c++  java
  • 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 ===  *****************************/
    
    
        }
    
    }
    
  • 相关阅读:
    乌龟棋 (codevs 1068)题解
    全排列 (codevs 1294)题解
    最小伤害 题解
    编码问题 题解
    基础DAY3-运算符 逻辑运算符 if elif
    图解算法——合并k个排序列表(Merge k Sorted Lists)
    算法图解——组合求和( Combination Sum)
    make命令使用 & makefile编写详解
    并发工具CountDownLatch源码分析
    线程局部变量ThreadLocal实现原理
  • 原文地址:https://www.cnblogs.com/ljmatlight/p/9060784.html
Copyright © 2011-2022 走看看