学习 Spring 实现 Bean 的定义、注册、获取

学习文档来自小傅哥,详情可以去原文章了解,这边只是简单记录一下学习体会
《Spring 手撸专栏》第 3 章:初显身手,运用设计模式,实现 Bean 的定义、注册、获取

一、工程结构

类似是这样,我这边稍微有点区别,仅做参考

small-spring-step-02
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.springframework.beans
    │           ├── factory
    │           │   ├── config
    │           │   │   ├── BeanDefinition.java
    │           │   │   └── SingletonBeanRegistry.java
    │           │   ├── support
    │           │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   ├── AbstractBeanFactory.java
    │           │   │   ├── BeanDefinitionRegistry.java
    │           │   │   ├── DefaultListableBeanFactory.java
    │           │   │   └── DefaultSingletonBeanRegistry.java
    │           │   └── BeanFactory.java
    │           └── BeansException.java
    └── test
        └── java
            └── cn.bugstack.springframework.test
                ├── bean
                │   └── UserService.java
                └── ApiTest.java

我这边先把主要代码的结构放出来,可以参考,在idea按CTRL + H 就可以看到类的层次结构了(很重要,不然等会很多继承和实现会把你绕晕的)

类关系:

image

类关系图:

image

类关系UML图:

image

二、代码实现

我这边就按代码层次结构从上到下来展示代码示例

BeanDefinition

定义一个被 Spring 容器管理的 Bean 对象

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;
    }
}

2.1 单例注册接口定义和实现

SingletonBeanRegistry

SingletonBeanRegistry 类定义了一个获取单例对象的接口

public interface SingletonBeanRegistry {

    Object getSingleton(String beanName);

}

DefaultSingletonBeanRegistry

DefaultSingletonBeanRegistry 类实现 getSingleton 方法,又定义了一个受保护的 addSingleton 方法。

具体来说,protected 访问修饰符的访问权限如下:

tips:具体来说,protected 访问修饰符的访问权限如下:
1.类内部:可以访问自身的 protected 成员;
2.同一包内的其他类:可以访问类的 protected 成员;
3.包的子类:可以访问父类的 protected 成员,前提是子类与父类不在同一个包中;
4.包的非子类:无法访问类的 protected 成员。

import com.lin.test.springframework.beans.factory.config.SingletonBeanRegistry;

import java.util.HashMap;
import java.util.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);
    }

}

2.2 抽象类定义模板方法

BeanFactory

BeanFactory 的定义由 AbstractBeanFactory 抽象类实现接口的 `getBean() 方法

public interface BeanFactory {

    Object getBean(String name);

}

AbstractBeanFactory

  • AbstractBeanFactory 首先继承了 DefaultSingletonBeanRegistry,也就具备了使用单例注册类方法。
  • 接下来很重要的一点是关于接口 BeanFactory 的实现,在方法 getBean 的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。那么 getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法 getBeanDefinitioncreateBean,由实现此抽象类的其他类做相应实现。
  • 后续继承抽象类 AbstractBeanFactory 的类有两个,包括:AbstractAutowireCapableBeanFactoryDefaultListableBeanFactory,这两个类分别做了相应的实现处理
import com.lin.test.springframework.beans.factory.BeanFactory;
import com.lin.test.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.BeansException;

public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {

    @Override
    public Object getBean(String name) {
        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;
}

2.3 实例化Bean类

  • AbstractAutowireCapableBeanFactory 类中实现了 Bean 的实例化操作 newInstance
  • 在处理完 Bean 对象的实例化后,直接调用 addSingleton 方法存放到单例对象的缓存中去。

AbstractAutowireCapableBeanFactory

import com.lin.test.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.BeansException;

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
        Object bean;
        try {
            bean = beanDefinition.getBeanClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BeansException("Instantiation of bean failed", e) {
            };
        }
        addSingleton(beanName, bean);
        return bean;
    }
}

2.4 核心类实现

DefaultListableBeanFactory

  • DefaultListableBeanFactorySpring 源码中也是一个非常核心的类,在我们目前的实现中也是逐步贴近于源码,与源码类名保持一致。
  • DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory 类,也就具备了接口 BeanFactoryAbstractBeanFactory 等一连串的功能实现。所以有时候你会看到一些类的强转,调用某些方法,也是因为你强转的类实现接口或继承了某些类。
  • 除此之外这个类还实现了接口 BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法,当然你还会看到一个 getBeanDefinition 的实现,这个方法我们文中提到过它是抽象类 AbstractBeanFactory 中定义的抽象方法。现在注册 Bean 定义与获取 Bean 定义就可以同时使用了,是不感觉这个套路还蛮深的。接口定义了注册,抽象类定义了获取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap
import com.lin.test.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.BeansException;

import java.util.HashMap;
import java.util.Map;

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new BeansException("No bean named '" + beanName + "' is defined"){};
        }
        return beanDefinition;
    }

}

三、测试

定义一个测试的业务类

public class UserService {

    public void queryUserInfo(){
        System.out.println("查询用户信息");
    }

}
import com.lin.test.bean.UserService;
import com.lin.test.springframework.beans.factory.config.BeanDefinition;
import com.lin.test.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Objects;


@SpringBootTest
class SpringframeworkTest {

    @Test
    public void testBeanFactory() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
        beanFactory.registerBeanDefinition("userService", beanDefinition);
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.queryUserInfo();
        UserService userService_singleton = (UserService) beanFactory.getBean("userService");
        userService_singleton.queryUserInfo();
        boolean equals = Objects.equals(userService, userService_singleton);
        System.out.println(equals);
    }

}

输出:

查询用户信息
查询用户信息
true

这里会有两次测试信息,一次是获取 Bean 时直接创建的对象,另外一次是从缓存中获取的实例化对象。

总结,在 Spring Bean 容器的实现类中要重点关注类之间的职责和关系,几乎所有的程序功能设计都离不开接口、抽象类、实现、继承,而这些不同特性类的使用就可以非常好的隔离开类的功能职责和作用范围。而这样的知识点也是在学习手写 Spring Bean 容器框架过程非常重要的知识。

posted @ 2024-01-15 15:14  启航黑珍珠号  阅读(79)  评论(0)    收藏  举报