zoukankan      html  css  js  c++  java
  • 框架源码系列二:手写Spring-IOC和Spring-DI(IOC分析、IOC设计实现、DI分析、DI实现)

    一、IOC分析

    1. IOC是什么?

    IOC:Inversion of Control控制反转,也称依赖倒置(反转)

    问题:如何理解控制反转?

    反转:依赖对象的获得被反转了。由自己创建,反转为从IOC容器中获取(和自动注入)

    2. IOC容器带来什么好处?

      1)代码更简洁,不需要去new需要使用的对象了。

      2)面向接口编程,使用者与具体类解耦,易扩展、替换实现者。

      3)可以方便进行AOP增强。进行AOP的前提是有IOC

    3. IOC容器做什么工作?

      IOC容器的工作:负责创建、管理类实例,向使用者提供实例。

    4. IOC容器是否是工厂模式的实例?

      是的。IOC容器负责来创建类实例对象,使用者需要实例就从IOC容器中get。也称IOC容器为bean工厂。

    二、IOC设计实现

    1. IOC容器的工作

    创建、管理bean。它是一个工厂,负责对外提供bean实例。

    问:bean是什么?

      bean是组件,就是类对象!

    1)IOC容器应该具备什么行为(对外接口)?

      对外提供bean实例,getBean()方法

    2) 这个getBean()方法是否需要参数?需要几个参数、什么类型的参数?

      简单工厂模式中,当工厂能创建很多类产品时,如要创建某类产品,需要告诉工厂。

    3)这个getBean()方法的返回值应是什么类型?

      各种类型的bean,那就只能是Object了。

    经过上面的问题Bean工厂的接口就可以定义出来了!!!

    2. Bean工厂接口:

    Bean工厂代码:

    package com.study.spring.beans;
    
    /**
     * 
     * @Description: IOC容器(bean工厂)接口:负责创建bean实例
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public interface BeanFactory {
        /**
         * 获取bean
         * 
         * @param name bean的名字
         *            
         * @return bean 实例
         * @throws Exception
         */
        Object getBean(String name) throws Exception;
    }

     Bean工厂怎么知道该如何创建bean?

    如何告诉Bean工厂?

      就是一个定义注册,我们可以给它定义一个bean定义注册接口

    3. Bean定义注册接口

     

    Bean定义注册接口代码:

    package com.study.spring.beans;
    
    /**
     * 
     * @Description: bean定义BeanDefinition定义好了就需要告诉IOC容器(bean工厂):
     * 通过bean定义注册接口BeanDefinitionRegistry把bean定义BeanDefinition注册到IOC容器(bean工厂)BeanFactory
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public interface BeanDefinitionRegistry {
    
        //注册bean定义
        void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException;
    
        //获取bean定义
        BeanDefinition getBeanDefinition(String beanName);
    
        //判断是否包含bean定义
        boolean containsBeanDefinition(String beanName);
    
    }

    4. Bean定义

    问题1:bean定义的用途是什么?

    告诉Bean工厂该如何创建某类bean

    问题2:获得类的实例的方式有哪些?

     new 构造方法

    Person p = new Person();

    工厂方法

    静态的

    public class PersonFactory {
        public static Person getPerson() {
            return new Person();
        }
    }

    成员方法

    public class PersonFactory {
        public Person getPerson() {
            return new Person();
        }
    }

    问题3:Bean工厂帮我们创建bean时,它需要获知哪些信息?

    1)new 构造方法的方式创建bean时,Bean工厂需要知道要创建的类的类名

    2)静态工厂方法的方式创建bean时,Bean工厂需要知道工厂类名、工厂方法名

    3)成员工厂方法的方式创建bean时,Bean工厂需要知道工厂类名(工厂bean名)、工厂方法名

      因为需要获取工厂类对象去调用工厂方法名创建bean,所以直接给工厂bean名先创建工厂bean对象

    问题4:每次从Bean工厂获取bean实例时,是否都需要创建一个新的?

      否,有的只需要单实例

    问题5:Bean定义是给Bean工厂创建bean用的,那么Bean定义接口应向Bean工厂提供哪些方法?

    new 构造方法的方式创建bean时,需要告诉bean工厂怎么获取类的名称——获取bean的类名:getBeanClass (): Class

    静态工厂方法的方式创建bean时,需要告诉bean工厂怎么获取工厂方法名:getFactoryMethodName() : String

    成员工厂方法的方式创建bean时,需要告诉bean工厂怎么获取工厂bean名:getFactoryBeanName() : String

    是否是单例等方法:getScope() : Sting、isSingleton()、isPrototype()

    问题6:类对象交给IOC容器来管理,类对象的生命周期中还可能有什么生命阶段事情要做吗?

    比如创建对象后可能需要进行一些初始化

    还有一些对象在销毁时可能要进行一些特定的销毁逻辑(如释放资源)

    那就在Bean定义中提供让用户可指定初始化、销毁方法。

    对Bean工厂就需提供getInitMethodName()、getDestroyMethodName()

    5. Bean定义接口

     

    bean定义接口BeanDefinition代码:

    package com.study.spring.beans;
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * 
     * @Description: bean定义接口:要IOC容器(bean工厂)创建bean实例,就得告诉IOC容器(bean工厂)需要创建什么样的bean-BeanDefinition
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public interface BeanDefinition {
    
        String SCOPE_SINGLETION = "singleton";
    
        String SCOPE_PROTOTYPE = "prototype";
    
        /**
         * 类:new 构造方法的方式创建bean时,需要告诉bean工厂怎么获取类的名称
         */
        Class<?> getBeanClass();
    
        /**
         * Scope
         */
        String getScope();
    
        /**
         * 是否单例
         */
        boolean isSingleton();
    
        /**
         * 是否原型
         */
        boolean isPrototype();
    
        /**
         * 工厂bean名:成员工厂方法的方式创建bean时,需要告诉bean工厂怎么获取工厂bean名
         */
        String getFactoryBeanName();
    
        /**
         * 工厂方法名:静态工厂方法的方式创建bean时,需要告诉bean工厂怎么获取工厂方法名
         */
        String getFactoryMethodName();
    
        /**
         * 初始化方法
         */
        String getInitMethodName();
    
        /**
         * 销毁方法
         */
        String getDestroyMethodName();
    
        /**
         * 校验bean定义的合法性
         */
        default boolean validate() {
            // 没定义class,工厂bean或工厂方法没指定,则不合法。
            if (this.getBeanClass() == null) {
                if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
                    return false;
                }
            }
    
            // 定义了类,又定义工厂bean,不合法
            if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
                return false;
            }
    
            return true;
        }
    
    }

     实现bean定义接口BeanDefinition实现一个通用的bean定义GenericBeanDefinition

    package com.study.spring.beans;
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * 
     * @Description: bean定义有了就需要实现bean定义接口BeanDefinition实现一个通用的bean
     * 定义GenericBeanDefinition,用来承载数据
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public class GenericBeanDefinition implements BeanDefinition {
    
        //bean的名称
        private Class<?> beanClass;
    
        //scope 默认单例
        private String scope = BeanDefinition.SCOPE_SINGLETION;
    
        //工厂bean名
        private String factoryBeanName;
    
        //工厂方法名
        private String factoryMethodName;
    
        //初始化方法
        private String initMethodName;
    
        //销毁方法
        private String destroyMethodName;
    
        //设置bean的名称
        public void setBeanClass(Class<?> beanClass) {
            this.beanClass = beanClass;
        }
    
        //设置scope
        public void setScope(String scope) {
            if (StringUtils.isNotBlank(scope)) {
                this.scope = scope;
            }
        }
    
        //设置工厂bean名
        public void setFactoryBeanName(String factoryBeanName) {
            this.factoryBeanName = factoryBeanName;
        }
    
        //设置工厂方法名
        public void setFactoryMethodName(String factoryMethodName) {
            this.factoryMethodName = factoryMethodName;
        }
    
        //设置初始化方法
        public void setInitMethodName(String initMethodName) {
            this.initMethodName = initMethodName;
        }
    
        //设置销毁方法
        public void setDestroyMethodName(String destroyMethodName) {
            this.destroyMethodName = destroyMethodName;
        }
    
        @Override
        public Class<?> getBeanClass() {
            return this.beanClass;
        }
    
        @Override
        public String getScope() {
            return this.scope;
        }
    
        @Override
        public boolean isSingleton() {
            return BeanDefinition.SCOPE_SINGLETION.equals(this.scope);
        }
    
        @Override
        public boolean isPrototype() {
            return BeanDefinition.SCOPE_PROTOTYPE.equals(this.scope);
        }
    
        @Override
        public String getFactoryBeanName() {
            return this.factoryBeanName;
        }
    
        @Override
        public String getFactoryMethodName() {
            return this.factoryMethodName;
        }
    
        @Override
        public String getInitMethodName() {
            return this.initMethodName;
        }
    
        @Override
        public String getDestroyMethodName() {
            return this.destroyMethodName;
        }
    
        @Override
        public String toString() {
            return "GenericBeanDefinition [beanClass=" + beanClass + ", scope=" + scope + ", factoryBeanName="
                    + factoryBeanName + ", factoryMethodName=" + factoryMethodName + ", initMethodName=" + initMethodName
                    + ", destroyMethodName=" + destroyMethodName + "]";
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((beanClass == null) ? 0 : beanClass.hashCode());
            result = prime * result + ((destroyMethodName == null) ? 0 : destroyMethodName.hashCode());
            result = prime * result + ((factoryBeanName == null) ? 0 : factoryBeanName.hashCode());
            result = prime * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode());
            result = prime * result + ((initMethodName == null) ? 0 : initMethodName.hashCode());
            result = prime * result + ((scope == null) ? 0 : scope.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            GenericBeanDefinition other = (GenericBeanDefinition) obj;
            if (beanClass == null) {
                if (other.beanClass != null)
                    return false;
            } else if (!beanClass.equals(other.beanClass))
                return false;
            if (destroyMethodName == null) {
                if (other.destroyMethodName != null)
                    return false;
            } else if (!destroyMethodName.equals(other.destroyMethodName))
                return false;
            if (factoryBeanName == null) {
                if (other.factoryBeanName != null)
                    return false;
            } else if (!factoryBeanName.equals(other.factoryBeanName))
                return false;
            if (factoryMethodName == null) {
                if (other.factoryMethodName != null)
                    return false;
            } else if (!factoryMethodName.equals(other.factoryMethodName))
                return false;
            if (initMethodName == null) {
                if (other.initMethodName != null)
                    return false;
            } else if (!initMethodName.equals(other.initMethodName))
                return false;
            if (scope == null) {
                if (other.scope != null)
                    return false;
            } else if (!scope.equals(other.scope))
                return false;
            return true;
        }
    
    }

     我们继续看下面的图:

     说明:bean定义BeanDefinition通过bean定义注册接口BeanDefinitionRegistry注册到Bean工厂BeanFactory,Bean工厂BeanFactory负责创建bean

    6. BeanFactory实现

     实现一个最基础的默认bean工厂:DefaultBeanFactory

     

    说明:

    6.1 实现bean定义信息注册接口

    问题1:bean定义信息如何存放?

      Map

    问题2:bean定义是否可以重名?重名怎么办?

      重名抛异常

    6.2 实现bean工厂

    问题1:创建的bean用什么存放,方便下次获取?

      Map,因为getBean是通过名字来取的,放在Map中更好

    问题2:在getBean方法中要做哪些事?

      创建bean实例,进行初始化

    6.3 Bean工厂实现代码:

    package com.study.spring.beans;
    
    import java.io.Closeable;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Objects;
    import java.util.concurrent.ConcurrentHashMap;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * 
     * @Description: bean定义BeanDefinition有了,bean定义注册BeanDefinitionRegistry也有了,
     * 就可以实现一个默认的bean工厂DefaultBeanFactory来创建bean实例了,DefaultBeanFactory除了需要实现BeanFactory外,
     * 还需要实现Bean定义注册接口BeanDefinitionRegistry,因为要把bean定义注册到bean工厂里面
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {
    
        private final Log logger = LogFactory.getLog(getClass());
    
        //用Map来存放bean定义信息
        private Map<String, BeanDefinition> beanDefintionMap = new ConcurrentHashMap<>(256);
    
        //用Map来存放创建的bean实例,注意这里只是存放单例bean,多实例每次都要创建新的,不需要存放
        private Map<String, Object> beanMap = new ConcurrentHashMap<>(256);
    
        //注册bean定义
        @Override
        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionRegistException {
            //判断给入的beanName和beanDefinition不能为空
            Objects.requireNonNull(beanName, "注册bean需要给入beanName");
            Objects.requireNonNull(beanDefinition, "注册bean需要给入beanDefinition");
    
            // 校验给入的bean是否合法
            if (!beanDefinition.validate()) {
                throw new BeanDefinitionRegistException("名字为[" + beanName + "] 的bean定义不合法:" + beanDefinition);
            }
    
            //如果已存在bean定义就抛异常
            if (this.containsBeanDefinition(beanName)) {
                throw new BeanDefinitionRegistException(
                        "名字为[" + beanName + "] 的bean定义已存在:" + this.getBeanDefinition(beanName));
            }
    
            //把bean定义放到Map里面
            this.beanDefintionMap.put(beanName, beanDefinition);
        }
    
        //根据bean的名字从Map里面获取bean定义
        @Override
        public BeanDefinition getBeanDefinition(String beanName) {
            return this.beanDefintionMap.get(beanName);
        }
    
        //根据bean的名字判断Map里面是否包含bean定义
        @Override
        public boolean containsBeanDefinition(String beanName) {
    
            return this.beanDefintionMap.containsKey(beanName);
        }
    
        //根据bean的名字获取bean实例,里面主要做的工作是创建bean实例和对bean实例进行初始化
        @Override
        public Object getBean(String name) throws Exception {
            return this.doGetBean(name);
        }
    
        //根据bean的名字获取bean实例,里面主要做的工作是创建bean实例和对bean实例进行初始化
        protected Object doGetBean(String beanName) throws Exception {
            //判断给入的bean名字不能为空
            Objects.requireNonNull(beanName, "beanName不能为空");
    
            //先从beanMap里面获取bean实例
            Object instance = beanMap.get(beanName);
    
            //如果beanMap里面已存在bean实例就直接返回,不需要走后面的流程了
            if (instance != null) {
                return instance;
            }
    
            //从beanDefintionMap里面获取bean定义信息
            BeanDefinition bd = this.getBeanDefinition(beanName);
            //bean定义信息不能为空
            Objects.requireNonNull(bd, "beanDefinition不能为空");
    
            //获取bean的类型
            Class<?> type = bd.getBeanClass();
            if (type != null) {
                //如果bean的类型不为空,并且工厂方法名为空,说明是使用构造方法的方式来创建bean实例
                if (StringUtils.isBlank(bd.getFactoryMethodName())) {
                    // 构造方法来构造对象
                    instance = this.createInstanceByConstructor(bd);
                } 
                //如果bean的类型不为空,并且工厂方法名不为空,说明是使用静态工厂方法的方式来创建bean实例
                else {
                    // 静态工厂方法
                    instance = this.createInstanceByStaticFactoryMethod(bd);
                }
            } 
            //如果bean的类型为空,说明是使用工厂bean的方式来创建bean实例
            else {
                // 工厂bean方式来构造对象
                instance = this.createInstanceByFactoryBean(bd);
            }
    
            // 执行初始化方法
            this.doInit(bd, instance);
    
            //存放单例的bean到beanMap
            if (bd.isSingleton()) {
                beanMap.put(beanName, instance);
            }
    
            return instance;
        }
    
        // 构造方法来构造对象 反射
        private Object createInstanceByConstructor(BeanDefinition bd)
                throws InstantiationException, IllegalAccessException {
            try {
                //拿到bean的类型,然后调用newInstance通过反射来创建bean实例
                return bd.getBeanClass().newInstance();
            } catch (SecurityException e1) {
                logger.error("创建bean的实例异常,beanDefinition:" + bd, e1);
                throw e1;
            }
        }
    
        // 静态工厂方法 反射
        private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {
            //拿到bean的类型
            Class<?> type = bd.getBeanClass();
            //通过静态工厂方法方法的名字getFactoryMethodName反射出bean的方法m创建bean实例
            Method m = type.getMethod(bd.getFactoryMethodName(), null);
            return m.invoke(type, null);
        }
    
        // 工厂bean方式来构造对象 反射
        private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {
    
            //通过bean定义信息中工厂bean的名字获取工厂bean的实例
            Object factoryBean = this.doGetBean(bd.getFactoryBeanName());
    
            //通过bean定义信息中工厂方法的名字反射出工厂bean的方法m创建bean实例
            Method m = factoryBean.getClass().getMethod(bd.getFactoryMethodName(), null);
            return m.invoke(factoryBean, null);
        }
    
        //执行初始化方法
        private void doInit(BeanDefinition bd, Object instance) throws Exception {
            // 获取bean定义中的初始化方法,如果存在初始化方法就通过反射去执行初始化方法
            if (StringUtils.isNotBlank(bd.getInitMethodName())) {
                Method m = instance.getClass().getMethod(bd.getInitMethodName(), null);
                m.invoke(instance, null);
            }
        }
    
        //销毁
        @Override
        public void close() throws IOException {
            // 执行单例实例的销毁方法
            for (Entry<String, BeanDefinition> e : this.beanDefintionMap.entrySet()) {
                String beanName = e.getKey();
                BeanDefinition bd = e.getValue();
    
                //获取bean定义中的销毁方法,如果存在销毁方法就通过反射去执行销毁方法
                if (bd.isSingleton() && StringUtils.isNotBlank(bd.getDestroyMethodName())) {
                    Object instance = this.beanMap.get(beanName);
                    try {
                        Method m = instance.getClass().getMethod(bd.getDestroyMethodName(), null);
                        m.invoke(instance, null);
                    } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                            | InvocationTargetException e1) {
                        logger.error("执行bean[" + beanName + "] " + bd + " 的 销毁方法异常!", e1);
                    }
                }
            }
        }
    }

     6.4 扩展DefaultBeanFactory

     对于单例bean,我们可以提前实例化,这样做的好处是不用在需要的时候再取获取了,可以保证线程安全,提高性能

    package com.study.spring.beans;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * 
     * @Description: 提前实例化单例bean
     * @author leeSmall
     * @date 2018年11月27日
     *
     */
    public class PreBuildBeanFactory extends DefaultBeanFactory {
    
        private final Log logger = LogFactory.getLog(getClass());
    
        private List<String> beanNames = new ArrayList<>();
    
        @Override
        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionRegistException {
            super.registerBeanDefinition(beanName, beanDefinition);
            synchronized (beanNames) {
                beanNames.add(beanName);
            }
        }
    
        public void preInstantiateSingletons() throws Exception {
            synchronized (beanNames) {
                for (String name : beanNames) {
                    BeanDefinition bd = this.getBeanDefinition(name);
                    if (bd.isSingleton()) {
                        this.doGetBean(name);
                        if (logger.isDebugEnabled()) {
                            logger.debug("preInstantiate: name=" + name + " " + bd);
                        }
                    }
                }
            }
        }
    }

    6.5 测试IOC容器(bean工厂)创建bean实例

     需要创建的bean实例ABean

    package com.study.spring.samples;
    
    /**
     * 
     * @Description: 需要创建的bean实例ABean
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public class ABean {
    
        public void doSomthing() {
            System.out.println(System.currentTimeMillis() + " " + this);
        }
    
        public void init() {
            System.out.println("ABean.init() 执行了");
        }
    
        public void destroy() {
            System.out.println("ABean.destroy() 执行了");
        }
    }

     创建bean实例ABean的工厂ABeanFactory

    package com.study.spring.samples;
    
    /**
     * 
     * @Description: 创建bean实例ABean的工厂ABeanFactory
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public class ABeanFactory {
    
        //静态工厂方式
        public static ABean getABean() {
            return new ABean();
        }
    
        //工厂bean的方式
        public ABean getABean2() {
            return new ABean();
        }
    }

     测试IOC容器(bean工厂)创建bean实例ABean

    package v1;
    
    import org.junit.AfterClass;
    import org.junit.Test;
    
    import com.dn.spring.beans.BeanDefinition;
    import com.dn.spring.beans.DefaultBeanFactory;
    import com.dn.spring.beans.GenericBeanDefinition;
    import com.dn.spring.samples.ABean;
    import com.dn.spring.samples.ABeanFactory;
    
    /**
     * 
     * @Description: 测试IOC容器(bean工厂)创建bean实例ABean
     * @author leeSmall
     * @date 2018年11月29日
     *
     */
    public class DefaultBeanFactoryTest {
    
        static DefaultBeanFactory bf = new DefaultBeanFactory();
    
        //测试构造方法方式创建bean实例
        @Test
        public void testRegist() throws Exception {
    
            //创建bean定义
            GenericBeanDefinition bd = new GenericBeanDefinition();
    
            //设置bean的类名
            bd.setBeanClass(ABean.class);
            //设置是否单例
            bd.setScope(BeanDefinition.SCOPE_SINGLETION);
            // bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    
            //设置bean的初始化方法
            bd.setInitMethodName("init");
            //设置bean的销毁方法
            bd.setDestroyMethodName("destroy");
    
            //把bean定义注册到bean工厂DefaultBeanFactory bf
            bf.registerBeanDefinition("aBean", bd);
    
        }
    
        //静态工厂方法的方式创建bean实例
        @Test
        public void testRegistStaticFactoryMethod() throws Exception {
            //创建bean定义
            GenericBeanDefinition bd = new GenericBeanDefinition();
            //设置工厂bean的名字
            bd.setBeanClass(ABeanFactory.class);
            //设置工厂方法名
            bd.setFactoryMethodName("getABean");
            //把bean定义注册到bean工厂DefaultBeanFactory bf
            bf.registerBeanDefinition("staticAbean", bd);
        }
    
        //工厂bean的方式创建bean实例
        @Test
        public void testRegistFactoryMethod() throws Exception {
            //创建工厂bean定义
            GenericBeanDefinition bd = new GenericBeanDefinition();
            //设置工厂bean的名字
            bd.setBeanClass(ABeanFactory.class);
            String fbname = "factory";
            //把工厂bean注册到bean工厂DefaultBeanFactory bf
            bf.registerBeanDefinition(fbname, bd);
    
            //创建bean定义
            bd = new GenericBeanDefinition();
            //设置工厂bean的名字
            bd.setFactoryBeanName(fbname);
            //设置工厂bean的方法名
            bd.setFactoryMethodName("getABean2");
            //设置是否是单列
            bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    
            //把bean定义注册到bean工厂DefaultBeanFactory bf
            bf.registerBeanDefinition("factoryAbean", bd);
        }
    
        //获取bean实例并调用里面的方法
        @AfterClass
        public static void testGetBean() throws Exception {
            System.out.println("构造方法方式------------");
            for (int i = 0; i < 3; i++) {
                ABean ab = (ABean) bf.getBean("aBean");
                ab.doSomthing();
            }
    
            System.out.println("静态工厂方法方式------------");
            for (int i = 0; i < 3; i++) {
                ABean ab = (ABean) bf.getBean("staticAbean");
                ab.doSomthing();
            }
    
            System.out.println("工厂方法方式------------");
            for (int i = 0; i < 3; i++) {
                ABean ab = (ABean) bf.getBean("factoryAbean");
                ab.doSomthing();
            }
    
            //销毁
            bf.close();
        }
    }

    输出结果:

    构造方法方式------------
    ABean.init() 执行了
    1543478493599 com.dn.spring.samples.ABean@46fbb2c1
    1543478493599 com.dn.spring.samples.ABean@46fbb2c1
    1543478493599 com.dn.spring.samples.ABean@46fbb2c1
    静态工厂方法方式------------
    1543478493599 com.dn.spring.samples.ABean@5ef04b5
    1543478493599 com.dn.spring.samples.ABean@5ef04b5
    1543478493599 com.dn.spring.samples.ABean@5ef04b5
    工厂方法方式------------
    1543478493599 com.dn.spring.samples.ABean@5f4da5c3
    1543478493600 com.dn.spring.samples.ABean@443b7951
    1543478493600 com.dn.spring.samples.ABean@14514713
    ABean.destroy() 执行了

    三、DI分析

    DI(Dependency Injection)依赖注入分析

    问题1:哪些地方会有依赖?

      构造参数依赖

      属性依赖

    问题2:依赖注入的本质是什么?

      赋值,给入构造参数值,给属性赋值

    问题3:参数值、属性值可能是什么值?

      直接值、bean依赖

    举例:

    public class Girl{
        public Girl(String name,int age,char cup,Boy boyfriend){
        }  
    
    }

    name,age,cup都是直接值,boyfriend是bean依赖

    问题4:直接值会有哪几种情况?

      基本数据类型、String

      数组、集合

      Properties

      Map

    本质:参数值、属性值都是值。bean工厂在进行依赖注入时,就是给入值。

    四、DI实现

    1. 构造参数依赖

     1.1 构造参数依赖定义分析

    public class Girl{
        public Girl(String name,int age,char cup,Boy boyfriend){
        }  
    
    }

    问题1:我们要创建一个Girl是如何创建的?

    Boy  leeSmall = new Boy("leeSmall");
    Girl girl = new Girl("小青",18,'D',leeSmall);

    直接把值传入构造函数即可

    问题2:我们可不可以这样来定义构造参数依赖?

      第一个参数值是:"小青"

      第二个参数值是:18

      第三个参数值是:'D'

      第四个参数值是:依赖一个Boy Bean

    完全可以!

    构造参数依赖设计

    问题1:参数可以有多个,用什么存储?

      集合:List

    问题2:参数有顺序,如何体现顺序?

      按参数顺序放入List

    问题3:参数可以值直接值,也可以是bean依赖,如何表示?

      因为可以有多种值,那就只能用Object

      List<Object>  constructorArgumentValues

    问题4:如果用Object来表示值,如何区分是Bean依赖?

      为Bean依赖定义一种数据类型BeanReference,bean工厂在构造Bean实例时,遍历判断参数是否是BeanReference,如果是则替换为依赖的bean实例。

    问题5:如果直接值是数组、集合等,它们的元素中有的是bean依赖,怎么处理?

      元素值还是用BeanReference,同样bean工厂在使用时需遍历替换。

    1.2 BeanReference

    BeanReference就是用来说明bean依赖的:依赖哪个Bean

    package com.dn.spring.beans;
    /**
     * 用于依赖注入中描述bean依赖
     */
    public class BeanReference {
        private String beanName;
    
        public BeanReference(String beanName) {
            super();
            this.beanName = beanName;
        }
    
        /**
         * 获得引用的beanName
         */
        public String getBeanName() {
            return this.beanName;
        }
    }

    1.3 在BeanDefinition中增加获得构造参数值的方法

    List<?> getConstructorArgumentValues();

    在GenericBeanDefinition中增加对应的实现

        //构造参数存放属性
        private List<?> constructorArgumentValues;
    
        //获得构造参数值
        public List<?> getConstructorArgumentValues() {
            return constructorArgumentValues;
        }
    
        //设置构造参数值
        public void setConstructorArgumentValues(List<?> constructorArgumentValues) {
            this.constructorArgumentValues = constructorArgumentValues;
        }

     构造参数依赖有了,下面就可以来实现构造参数依赖注入了!

    1.4 BeanFactory中实现构造参数依赖注入

    1.4.1 首先需要把bean定义中的构造参数引用转为真实的值,在DefaultBeanFactory中增加一个方法来干这事。

    代码实现:

        //把bean定义中的构造参数引用转为真实的值
        private Object[] getConstructorArgumentValues(BeanDefinition bd) throws Exception {
    
            return this.getRealValues(bd.getConstructorArgumentValues());
    
        }
    
        //把bean定义中的构造参数引用转为真实的值
        private Object[] getRealValues(List<?> defs) throws Exception {
            if (CollectionUtils.isEmpty(defs)) {
                return null;
            }
    
            Object[] values = new Object[defs.size()];
            int i = 0;
            Object v = null;
            for (Object rv : defs) {
                if (rv == null) {
                    v = null;
                } else if (rv instanceof BeanReference) {
                    v = this.doGetBean(((BeanReference) rv).getBeanName());
                } else if (rv instanceof Object[]) {
                    // TODO 处理集合中的bean引用
                } else if (rv instanceof Collection) {
                    // TODO 处理集合中的bean引用
                } else if (rv instanceof Properties) {
                    // TODO 处理properties中的bean引用
                } else if (rv instanceof Map) {
                    // TODO 处理Map中的bean引用
                } else {
                    v = rv;
                }
    
                values[i++] = v;
            }
    
            return values;
        }

    问题:有参数了,如何断定是哪个构造方法、哪个工厂方法?需要考虑下面的情况

    a)方法是可以重载的

    b)形参定义时可能是接口或者父类,实参则是具体的子实现

    c)可以通过反射获取提供的构造方法、方法,如下:

    java.lang.Class

    反射获取构造方法:

       //获取所有构造方法
       @CallerSensitive
        public Constructor<?>[] getConstructors() throws SecurityException {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
            return copyConstructors(privateGetDeclaredConstructors(true));
        }
        //获取指定构造方法
        @CallerSensitive
        public Constructor<T> getConstructor(Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
            return getConstructor0(parameterTypes, Member.PUBLIC);
        }

     反射获取方法:

        //获取所有方法
        @CallerSensitive
        public Method[] getMethods() throws SecurityException {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
            return copyMethods(privateGetPublicMethods());
        }
        //获取指定方法
        @CallerSensitive
        public Method getMethod(String name, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
            Method method = getMethod0(name, parameterTypes, true);
            if (method == null) {
                throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
            }
            return method;
        }

    判断逻辑:

    a)先根据参数的类型进行精确匹配查找,如未找到,则进行第二步查找;

    b)获得所有的构造方法遍历,通过参数数量过滤,再比对形参类型与实参类型

    1.4.2 当我们判断出构造方法或者工厂方法后,对于原型Bean,下次获取是否就可以省去判断了?

    也就是说,对于原型Bean,我们可以缓存下这个构造方法或工厂方法。如何实现?

    在BeanDefinition中增加缓存的方法:

        /* 下面的四个方法是供beanFactory中使用的 */
        //获取构造方法
        public Constructor<?> getConstructor();
    
        //缓存构造方法
        public void setConstructor(Constructor<?> constructor);
    
        //获取工厂方法
        public Method getFactoryMethod();
    
        //缓存工厂方法
        public void setFactoryMethod(Method factoryMethod);

     在GenericBeanDefinition中增加对应的实现:

        /* 下面的四个方法是供beanFactory中使用的 */
        //获取构造方法
        public Constructor<?> getConstructor() {
            return constructor;
        }
    
        //缓存构造方法
        public void setConstructor(Constructor<?> constructor) {
            this.constructor = constructor;
        }
    
        //获取工厂方法
        public Method getFactoryMethod() {
            return factoryMethod;
        }
    
        //缓存工厂方法
        public void setFactoryMethod(Method factoryMethod) {
            this.factoryMethod = factoryMethod;
        }

    1.4.3 接下来可以写查找构造方法或查找工厂方法的代码了

    1)在DefaultBeanFactory中增加查找构造方法的方法

        //查找构造方法的方法
        private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
    
            Constructor<?> ct = null;
    
            //如果参数为空,则返回无参的构造方法
            if (args == null) {
                return bd.getBeanClass().getConstructor(null);
            }
    
            // 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
            ct = bd.getConstructor();
            if (ct != null) {
                return ct;
            }
    
            // 先根据参数类型获取精确匹配的构造方法
            Class<?>[] paramTypes = new Class[args.length];
            int j = 0;
            for (Object p : args) {
                paramTypes[j++] = p.getClass();
            }
            try {
                ct = bd.getBeanClass().getConstructor(paramTypes);
            } catch (Exception e) {
                // 这个异常不需要处理
            }
    
            //如果根据参数类型进行精确批次查找没有找到构造方法,就获得所有的构造方法遍历,通过参数数量过滤,再比对形参类型与实参类型
            if (ct == null) {
    
                // 没有精确参数类型匹配的,则遍历匹配所有的构造方法
                // 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
                outer: for (Constructor<?> ct0 : bd.getBeanClass().getConstructors()) {
                    Class<?>[] paramterTypes = ct0.getParameterTypes();
                    if (paramterTypes.length == args.length) {
                        for (int i = 0; i < paramterTypes.length; i++) {
                            //isAssignableFrom方法表示是否可以把args[i].getClass()赋值给paramterTypes[i]
                            if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
                                continue outer;
                            }
                        }
    
                        ct = ct0;
                        break outer;
                    }
                }
            }
    
            //如果找到构造方法了,并且是原型的就缓存起来
            if (ct != null) {
                // 对于原型bean,可以缓存找到的构造方法,方便下次构造实例对象。在BeanDefinfition中获取设置所用构造方法的方法。
                // 同时在上面增加从beanDefinition中获取的逻辑。
                if (bd.isPrototype()) {
                    bd.setConstructor(ct);
                }
                return ct;
            } else {
                throw new Exception("不存在对应的构造方法!" + bd);
            }
        }

     2)修改DefaultBeanFactory中用构造方法创建实例的代码调用determineConstructor

        // 构造方法来构造对象
        private Object createInstanceByConstructor(BeanDefinition bd) throws Exception {
            try {
                //获取bean定义中的构造参数
                Object[] args = this.getConstructorArgumentValues(bd);
                //如果构造参数为空就使用无参构造函数
                if (args == null) {
                    return bd.getBeanClass().newInstance();
                } 
                //查找有参构造函数并返回
                else {
                    // 决定构造方法
                    return this.determineConstructor(bd, args).newInstance(args);
                }
            } catch (SecurityException e1) {
                logger.error("创建bean的实例异常,beanDefinition:" + bd, e1);
                throw e1;
            }
        }

    3)按照增加查找构造方法的方式修改静态工厂方法、工厂方法方式的参数依赖

    增加查找工厂方法的方法

        //查找工厂方法的方法
        private Method determineFactoryMethod(BeanDefinition bd, Object[] args, Class<?> type) throws Exception {
            if (type == null) {
                type = bd.getBeanClass();
            }
    
            //获取bean定义中国工厂方法的名字
            String methodName = bd.getFactoryMethodName();
    
            //如果参数为空就返回无参的方法
            if (args == null) {
                return type.getMethod(methodName, null);
            }
    
            Method m = null;
            // 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
            m = bd.getFactoryMethod();
            if (m != null) {
                return m;
            }
    
            // 先根据参数类型获取精确匹配的方法
            Class[] paramTypes = new Class[args.length];
            int j = 0;
            for (Object p : args) {
                paramTypes[j++] = p.getClass();
            }
            try {
                m = type.getMethod(methodName, paramTypes);
            } catch (Exception e) {
                // 这个异常不需要处理
            }
    
            //如果根据参数类型进行精确批次查找没有找到工厂方法,就获得所有的构造方法遍历,通过参数数量过滤,再比对形参类型与实参类型
            if (m == null) {
    
                // 没有精确参数类型匹配的,则遍历匹配所有的方法
                // 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
                outer: for (Method m0 : type.getMethods()) {
                    if (!m0.getName().equals(methodName)) {
                        continue;
                    }
                    Class<?>[] paramterTypes = m.getParameterTypes();
                    if (paramterTypes.length == args.length) {
                        for (int i = 0; i < paramterTypes.length; i++) {
                            //isAssignableFrom方法表示是否可以把args[i].getClass()赋值给paramterTypes[i]
                            if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
                                continue outer;
                            }
                        }
    
                        m = m0;
                        break outer;
                    }
                }
            }
    
            //如果找到构造方法了,并且是原型的就缓存起来
            if (m != null) {
                // 对于原型bean,可以缓存找到的方法,方便下次构造实例对象。在BeanDefinfition中获取设置所用方法的方法。
                // 同时在上面增加从beanDefinition中获取的逻辑。
                if (bd.isPrototype()) {
                    bd.setFactoryMethod(m);
                }
                return m;
            } else {
                throw new Exception("不存在对应的构造方法!" + bd);
            }
        }

    修改DefaultBeanFactory中用工厂方法创建实例的代码调用determineFactoryMethod

        // 静态工厂方法
        private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {
    
            Class<?> type = bd.getBeanClass();
            Object[] realArgs = this.getRealValues(bd.getConstructorArgumentValues());
            Method m = this.determineFactoryMethod(bd, realArgs, null);
            return m.invoke(type, realArgs);
        }
    
        // 工厂bean方式来构造对象
        private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {
    
            Object factoryBean = this.doGetBean(bd.getFactoryBeanName());
            Object[] realArgs = this.getRealValues(bd.getConstructorArgumentValues());
            Method m = this.determineFactoryMethod(bd, realArgs, factoryBean.getClass());
    
            return m.invoke(factoryBean, realArgs);
        }

    1.4.4 测试

    参数依赖注入测试

    package v2;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.junit.Test;
    
    import com.dn.spring.beans.BeanReference;
    import com.dn.spring.beans.GenericBeanDefinition;
    import com.dn.spring.beans.PreBuildBeanFactory;
    import com.dn.spring.samples.ABean;
    import com.dn.spring.samples.ABeanFactory;
    import com.dn.spring.samples.CBean;
    import com.dn.spring.samples.CCBean;
    
    /**
     * 
     * @Description: 参数依赖注入测试
     * @author leeSmall
     * @date 2018年12月1日
     *
     */
    public class DItest {
        static PreBuildBeanFactory bf = new PreBuildBeanFactory();
    
        //构造函数参数依赖注入
        @Test
        public void testConstructorDI() throws Exception {
    
            GenericBeanDefinition bd = new GenericBeanDefinition();
            bd.setBeanClass(ABean.class);
            List<Object> args = new ArrayList<>();
            args.add("abean01");
            args.add(new BeanReference("cbean"));
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("abean", bd);
    
            bd = new GenericBeanDefinition();
            bd.setBeanClass(CBean.class);
            args = new ArrayList<>();
            args.add("cbean01");
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("cbean", bd);
    
            bf.preInstantiateSingletons();
    
            ABean abean = (ABean) bf.getBean("abean");
    
            abean.doSomthing();
        }
    
        //静态工厂方法参数依赖注入
        @Test
        public void testStaticFactoryMethodDI() throws Exception {
    
            GenericBeanDefinition bd = new GenericBeanDefinition();
            bd.setBeanClass(ABeanFactory.class);
            bd.setFactoryMethodName("getABean");
            List<Object> args = new ArrayList<>();
            args.add("abean02");
            args.add(new BeanReference("cbean02"));
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("abean02", bd);
    
            bd = new GenericBeanDefinition();
            bd.setBeanClass(CBean.class);
            args = new ArrayList<>();
            args.add("cbean02");
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("cbean02", bd);
    
            bf.preInstantiateSingletons();
    
            ABean abean = (ABean) bf.getBean("abean02");
    
            abean.doSomthing();
        }
    
        //普通工厂方法的参数依赖注入
        @Test
        public void testFactoryMethodDI() throws Exception {
    
            GenericBeanDefinition bd = new GenericBeanDefinition();
            bd.setFactoryBeanName("abeanFactory");
            bd.setFactoryMethodName("getABean2");
            List<Object> args = new ArrayList<>();
            args.add("abean03");
            args.add(new BeanReference("cbean02"));
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("abean03", bd);
    
            bd = new GenericBeanDefinition();
            bd.setBeanClass(ABeanFactory.class);
            bf.registerBeanDefinition("abeanFactory", bd);
    
            bf.preInstantiateSingletons();
    
            ABean abean = (ABean) bf.getBean("abean03");
    
            abean.doSomthing();
        }
    
    }

    输出结果:

    调用了含有CBean参数的构造方法
    1543644406604 abean01 cb.name=cbean01
    
    调用了含有CBean参数的构造方法
    1543644406607 abean02 cb.name=cbean02
    
    调用了含有CBean参数的构造方法
    1543644406608 abean03 cb.name=cbean02

    1.4.5 循环依赖如何处理

    问题:构造对象时可以循环依赖吗/

    构造实例对象时的循环依赖,会陷入僵死局面,是不允许构造实例时的循环依赖的。那么怎么发现循环依赖呢?

    发现循环依赖的方法:加入一个正在构造的bean的记录,每个bean开始构造时加入该记录中,构造完成后从记录中移除。如果有依赖,先看依赖的bean是否在构造中,如是就构成了循环依赖,抛出异常

    代码实现:

    在DefaultBeanFactory增加如下代码:

            //记录正在构造的bean
        private ThreadLocal<Set<String>> buildingBeans = new ThreadLocal<>();
    
            // 记录正在创建的Bean
            Set<String> ingBeans = this.buildingBeans.get();
            if (ingBeans == null) {
                ingBeans = new HashSet<>();
                this.buildingBeans.set(ingBeans);
            }
    
            // 检测循环依赖 因为如果已bean正在构造,这时发现有其他的bean依赖它,此时它又没有创建好久需要抛异常了
            if (ingBeans.contains(beanName)) {
                throw new Exception(beanName + " 循环依赖!" + ingBeans);
            }
    
            // 记录正在创建的Bean
            ingBeans.add(beanName);
                   .....................
                   ......................
            // 创建好实例后,移除创建中记录
            ingBeans.remove(beanName);

    循环依赖测试代码

    package v2;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.junit.Test;
    
    import com.dn.spring.beans.BeanReference;
    import com.dn.spring.beans.GenericBeanDefinition;
    import com.dn.spring.beans.PreBuildBeanFactory;
    import com.dn.spring.samples.DBean;
    import com.dn.spring.samples.EBean;
    
    /**
     * 
     * @Description: 循环依赖测试
     * @author leeSmall
     * @date 2018年12月1日
     *
     */
    public class CirculationDiTest {
    
        static PreBuildBeanFactory bf = new PreBuildBeanFactory();
    
        //DBean依赖EBean,EBean又依赖DBean 抛异常
        @Test
        public void testCirculationDI() throws Exception {
            GenericBeanDefinition bd = new GenericBeanDefinition();
            bd.setBeanClass(DBean.class);
            List<Object> args = new ArrayList<>();
            args.add(new BeanReference("ebean"));
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("dbean", bd);
    
            bd = new GenericBeanDefinition();
            bd.setBeanClass(EBean.class);
            args = new ArrayList<>();
            args.add(new BeanReference("dbean"));
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("ebean", bd);
    
            bf.preInstantiateSingletons();
        }
    }

    2. 属性依赖

    问题1:属性依赖是什么?

      某个属性依赖某个值,需要外部给入这个值

    问题2:该如何来描述一个属性依赖?

      属性名、值,定义一个来来表示这两个值

    问题3:会有多个属性依赖,怎么存放?

      List存放

    问题4:属性值得情况和构造参数值得情况一样吗?

      一样

    2.1 定义属性依赖实体

    属性依赖实体类类图如下:

    属性依赖实体类代码:

    package com.study.spring.beans;
    
    /**
     * 
     * @Description: 属性值依赖实体
     * @author leeSmall
     * @date 2018年12月1日
     *
     */
    public class PropertyValue {
    
        private String name;
    
        private Object value;
    
        public PropertyValue(String name, Object value) {
            super();
            this.name = name;
            this.value = value;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Object getValue() {
            return value;
        }
    
        public void setValue(Object value) {
            this.value = value;
        }
    
    }

     2.2 在BeanDefinition接口中增加获得属性依赖定义的方法

        /**
         * 获得属性依赖定义的方法
         * 
         */
        List<PropertyValue> getPropertyValues();

     2.3 在GenericBeanDefinition增加对应的实现

        //存放属性依赖
        private List<PropertyValue> propertyValues;
    
        //获取属性依赖
        public List<PropertyValue> getPropertyValues() {
            return propertyValues;
        }
    
        //设置属性依赖
        public void setPropertyValues(List<PropertyValue> propertyValues) {
            this.propertyValues = propertyValues;
        }

     2.4 在DefaultBeanFactory中实现属性依赖

        //属性依赖实现
        private void setPropertyDIValues(BeanDefinition bd, Object instance) throws Exception {
            //bean定义中没有属性依赖就直接返回
            if (CollectionUtils.isEmpty(bd.getPropertyValues())) {
                return;
            }
            //如果bean定义中有属性依赖就设置值,设置方式和构造参数的设置一样
            for (PropertyValue pv : bd.getPropertyValues()) {
                //属性依赖没有给名字就直接跳过
                if (StringUtils.isBlank(pv.getName())) {
                    continue;
                }
                //获取类对象
                Class<?> clazz = instance.getClass();
                //通过属性名获取类对象里面声明的字段
                Field p = clazz.getDeclaredField(pv.getName());
    
                //设置字段可访问
                p.setAccessible(true);
    
                //把属性值转化为真正的值,和构造参数一样
                Object rv = pv.getValue();
                Object v = null;
                if (rv == null) {
                    v = null;
                } else if (rv instanceof BeanReference) {
                    v = this.doGetBean(((BeanReference) rv).getBeanName());
                } else if (rv instanceof Object[]) {
                    // TODO 处理集合中的bean引用
                } else if (rv instanceof Collection) {
                    // TODO 处理集合中的bean引用
                } else if (rv instanceof Properties) {
                    // TODO 处理properties中的bean引用
                } else if (rv instanceof Map) {
                    // TODO 处理Map中的bean引用
                } else {
                    v = rv;
                }
    
                //把真正的值v设置到属性p里面 即属性p依赖的值v
                p.set(instance, v);
    
            }
        }

     在doGetBean(String beanName)中增加对设置属性依赖的调用

            // 给入属性依赖
            this.setPropertyDIValues(bd, instance);

    注意:属性依赖是允许循环依赖的,因为是在实例创建好之后才设置属性依赖的值的!!!

     2.5 属性依赖测试

    package v2;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.junit.Test;
    
    import com.dn.spring.beans.BeanReference;
    import com.dn.spring.beans.GenericBeanDefinition;
    import com.dn.spring.beans.PreBuildBeanFactory;
    import com.dn.spring.beans.PropertyValue;
    import com.dn.spring.samples.ABean;
    import com.dn.spring.samples.CBean;
    import com.dn.spring.samples.FBean;
    
    /**
     * 
     * @Description: 属性依赖测试
     * @author leeSmall
     * @date 2018年12月1日
     *
     */
    public class PropertyDItest {
        static PreBuildBeanFactory bf = new PreBuildBeanFactory();
    
        @Test
        public void testPropertyDI() throws Exception {
    
            //构造参数依赖
            GenericBeanDefinition bd = new GenericBeanDefinition();
            bd.setBeanClass(ABean.class);
            List<Object> args = new ArrayList<>();
            args.add("abean01");
            args.add(new BeanReference("cbean"));
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("abean", bd);
    
            //构造参数依赖
            bd = new GenericBeanDefinition();
            bd.setBeanClass(CBean.class);
            args = new ArrayList<>();
            args.add("cbean01");
            bd.setConstructorArgumentValues(args);
            bf.registerBeanDefinition("cbean", bd);
    
            //属性依赖
            bd = new GenericBeanDefinition();
            bd.setBeanClass(FBean.class);
            List<PropertyValue> propertyValues = new ArrayList<>();
            propertyValues.add(new PropertyValue("name", "FFBean01"));
            propertyValues.add(new PropertyValue("age", 18));
            propertyValues.add(new PropertyValue("aBean", new BeanReference("abean")));
            bd.setPropertyValues(propertyValues);
            bf.registerBeanDefinition("fbean", bd);
    
            bf.preInstantiateSingletons();
    
            FBean fbean = (FBean) bf.getBean("fbean");
            System.out.println("设置的属性依赖值: " + fbean.getName() + " " + fbean.getAge());
            fbean.getaBean().doSomthing();
        }
    
    }

    输出结果:

    调用了含有CBean参数的构造方法
    设置的属性依赖值: FFBean01 18
    1543649718902 abean01 cb.name=cbean01

     完整代码获取地址:

     Spring IOC分析和手写实现Spring IOC代码:https://github.com/leeSmall/FrameSourceCodeStudy/tree/master/spring-v1

    Spring DI分析和手写实现Spring DI代码:https://github.com/leeSmall/FrameSourceCodeStudy/tree/master/spring-v2

  • 相关阅读:
    快速排序
    fedora 配置
    while与do while
    switch选择结构
    if选择结构
    java有参
    java猜拳
    java类的无参方法
    java类与对象
    java数组
  • 原文地址:https://www.cnblogs.com/leeSmall/p/10023593.html
Copyright © 2011-2022 走看看