手撸Spring学习笔记-2

149 阅读3分钟

6fdeffd3e4a84e577d9480f632ca32d5.jpeg

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

一、前言

清明时节雨纷纷,路上行人欲断魂。借问酒家何处有?牧童遥指杏花村。

疫情不知不觉已经三年了,最近疫情反反复复,我老家也全面封控,在外的游子只能做到原地过节,不流动,不聚集,不给家乡添麻烦,在心里默默喊一句:鸡泽加油。

对于进入开发行业三到五年的小伙伴,你可以选择做一个完美的CRUD Boy,每天写写增删改查,但是你真的不想完善自己的技术体系,做一个高级开发,甚至做一个技术专家吗?躺平虽好,但要学着爬起来进行"内卷"哦,不是卷别人,而是卷自己。

二、正文

昨天,我们只是用一个简单的HashMap创建了一个简陋的Bean容器,今天让我们来完善。

  1. 首先,我们昨天进行Bean注册时,直接放了一个Object对象,这样是不行的,我们需要将这个实例化对象改成Class类信息,所以我们将BeanDefinition中的Object替换成 Class。将BeanDefinition类修改如下:

    public class BeanDefinition {
    ​
        private Class beanClass;
    ​
        public BeanDefinition(Class beanClass) {
            this.beanClass = beanClass;
        }
    ​
        public Class getBeanClass() {
            return beanClass;
        }
    ​
        public void setBeanClass(Class beanClass) {
            this.beanClass = beanClass;
        }
    }
    
  1. 然后我们需要定义一个BeanFactory的工厂接口,提供Bean的获取方法

    public interface BeanFactory {
    ​
        /**
         * 根据name获取bean对象的接口
         * @param name
         * @return
         * @throws BeansException
         */
        Object getBean(String name) throws BeansException;
    ​
    }
    
  2. 我们再来定义一个获取Bean对象的基于模板模式的抽象类,具体步骤为:先根据名称获取Bean的定义,再根据Bean的定义去实例化Bean对象。由于此对象只是定义获取Bean的过程,具体获取Bean定义和实例化Bean只提供抽象方法。

    public abstract class AbstractBeanFactory implements BeanFactory {
    ​
        /**
         * 根据Bean名称获取Bean对象
         * @param name
         * @return
         * @throws BeansException
         */
        @Override
        public Object getBean(String name) throws BeansException {
            
            BeanDefinition beanDefinition = getBeanDefinition(name);
    ​
            return createBean(name, beanDefinition);
        }
    ​
        protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
    ​
        protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
    }
    
  3. 我们在使用Spring的过程中,频繁的获取同一个Bean的实例化对象的时候,一般都是获取是同一个对象,所以我们要对实例化的对象进行单例处理。

    • 首先我们需定义一个单例注册的接口

      public interface SingletonBeanRegistry {
      ​
          Object getSingleton(String beanName);
      }
      
    • 对获取单例对象进行实现,并将实例化好的对象用map存放起来

      public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
      ​
          private Map<String, Object> singletonObjects = new HashMap<>();
      ​
          @Override
          public Object getSingleton(String beanName) {
              return singletonObjects.get(beanName);
          }
      ​
          protected void addSingleton(String beanName, Object singletonObject) {
              singletonObjects.put(beanName, singletonObject);
          }
      }
      
  4. 接下来,我们让AbstractBeanFactory继承DefaultSingletonBeanRegistry,是其具备使用获取单例的方法。同时,我们修改整个获取实例化Bean的流程,先去实例化容器里获取Bean,如果没有的情况下,再去创建。这样就满足了我们在使用过程中,获取的Bean都是同一个。

    public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
    ​
        /**
         * 根据Bean名称获取Bean对象
         * <p>
         *     1.根据 name 通过 DefaultSingletonBeanRegistry 父类的 getSingleton 方法去获取Bean 对象
         *     2.判断 Bean 对象是否存在
         *     3.不存在,先去获取 Bean 的定义类
         *     4.根据 Bean名称和定义去创建Bean对象
         * </p>
         * @param name
         * @return
         * @throws BeansException
         */
        @Override
        public Object getBean(String name) throws BeansException {
            Object bean = getSingleton(name);
    ​
            if (bean != null) {
                return bean;
            }
    ​
            BeanDefinition beanDefinition = getBeanDefinition(name);
    ​
            return createBean(name, beanDefinition);
        }
    ​
        protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
    ​
        protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
    }
    

在 Spring Bean 容器的实现类中要重点关注类之间的职责和关系,几乎所有的程序功能设计都离不开接口、抽象类、实现、继承,而这些不同特性类的使用就可以非常好的隔离开类的功能职责和作用范围。这就是第二天更文挑战的内容了,预知后事如何,且听下回分解。