极简Spring之IOC

1,431 阅读43分钟

AOP:juejin.cn/spost/73683…
高级部分:juejin.cn/post/736905…

简简单单写个IOC

菜鸟一枚,如果文档有错误的地方,请指正

阅读过Spring源码的人都知道,Spring封装之深,抽象程度之高令人咂舌,其分支太多,经常迷失在分支里忘记了主干在哪,或者说压根不知道主干在哪,不知道从哪开始读,没有一个阅读主线

文档从零开始实现一个最简单的IOC容器(Map集合),然后再此基础上一点点迭代实现Spring的功能,每次迭代所增加的类或代码都只实现了其本职最基础最简单的功能

参考github.com/DerekYRC/mi…

在一切开始前,准备几个类

人员类,省略了get、set等方法,懂的都懂

public class Person {
    private String name;
    private IDCard idCard;
    
    public Person(){}
    public Person(IDCard idCard, String name) {
        this.idCard = idCard;
        this.name = name;
    }
    
    public void sayHello() {
        SSystem.out.println("hello, my name is " + name + ", and my IdCard is " + idCard);
    }
}

身份证类

public class IDCard {
    private String idNumber;
    
    public IDCard(){}
    public IDCard(String idNumber){ this.idNumber = idNumber;}
}

异常类

public class BeansException extends RuntimeException {
    public BeansException(String msg) {super(msg);}
    public BeansException(String msg, Throwable cause) {super(msg, cause);}
}

1 最简单的IOC容器

IOC容器,本质就是存储Bean实例的容器,严格来说是存储单例Bean实例的容器,因为对于多例Bean,每次得到的都是一个新对象,不需要存储,每次获取时新创建就行了

其内部维护了一个Map集合,用来存储BeanName和Bean实例的映射

public class BeanFactory {
    //存储BeanName和Bean实例的映射
	private Map<String, Object> beanMap = new HashMap<>();

    //注册Bean实例,本质就是往Map中添加数据
	public void registerBean(String name, Object bean) {
		beanMap.put(name, bean);
	}

    //根据名称获取Bean
	public Object getBean(String name) {
		return beanMap.get(name);
	}
}

至此一个拥有基本功能的IOC容器就实现了

注册和获取bean本质就是从容器中添加和存放元素

测试我们的IOC容器

BeanFactory beanFactory = new BeanFactory();
beanFactory.registerBean("person", new Person());
Person person = (Person) beanFactory.getBean("person");
assert person != null;
person.sayHello();

2 BeanDefinition

BeanDefinition,也就是Bean定义对象,描述了一个Bean长什么样子,将来IOC容器根据BeanDefinition创建bean实例

这里为了简单,BeanDefinition只保存了Bean的class对象

public class BeanDefinition {
    //Bean的class对象
    private Class beanClass;

    public BeanDefinition(Class beanClass) {this.beanClass = beanClass;}

    public Class getBeanClass() {return beanClass;}
    public void setBeanClass(Class beanClass) {this.beanClass = beanClass;}
}

有了BeanDefinition,还需要一个容器用来存储所有的BeanDefinition,于是就有了BeanDefinitionRegistry

BeanDefinitionRegistry是BeanDefinition注册表接口,可以注册并保存BeanDefinition对象,所以应该有一个注册BeanDefinition的抽象方法,并且其实现类肯定有一个存储BeanDefinition的集合

public interface BeanDefinitionRegistry {
    //向BeanDefinition的注册表添加BeanDefinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
}

3 作用域之Singleton

BeanFactory的getBean可以得到所有的Bean,而Bean的作用域Scope分为单例、多例等类型

这些不同类型的Bean应该存储在不同的组件里,对应着不同的抽象

而BeanFactory作为统一对外提供的顶级IOC容器,可以聚合这些不同类型的组件

BeanFactory改造如下

public interface BeanFactory {
    //只有个getBean抽象方法
    Object getBean(String name) throws BeansException;
}

将单例Bean存储在SingletonBeanRegistry中

SingletonBeanRegistry是单例Bean的注册表接口,可以注册并维护所有单例类型的Bean

public interface SingletonBeanRegistry {
    //根据名称获取单例bean
    Object getSingleton(String beanName);
}

其实现类DefaultSingletonBeanRegistry维护了一个集合用于存储所有的单例Bean

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    //存放单例bean的集合
    private Map<String, Object> singletonObjects = new HashMap<>();

    //根据名称获取单例bean
    @Override
    public Object getSingleton(String beanName) {
        return singletonObjects.get(beanName);
    }
    //注册单例bean,也就是往集合中添加数据
    public void addSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
    }
}

4 一些经典BeanFactory实现类

AbstractBeanFactory翻译为抽象的Bean工厂,该容器负责得到Bean

实现了BeanFactory,所以是一个IOC容器,而又继承了DefaultSingletonBeanRegistry,因此可以维护所有单例Bean

public abstract class AbstractBeanFactory 
    extends DefaultSingletonBeanRegistry implements BeanFactory {
    //根据名称获取Bean对象
    @Override
    public Object getBean(String name) throws Exception {
        //先从单例bean注册表中获取
        Object singleton = getSingleton(name);
        if (singleton != null) {
            return singleton;
        }
        //如果从单例bean集合中没有找到bean,则需要创建
        BeanDefinition beanDefinition = getBeanDefinition(name);
        return createBean(name, beanDefinition);
    }

    //创建一个bean
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition)
        throws BeansException;
    //根据名称得到BeanDefinition
    protected abstract BeanDefinition getBeanDefinition(String beanName)
        throws BeansException;
}

名字带有Abstract,说明含有抽象方法需要被子类实现(createBean和getBeanDefinition)

AbstractAutowireCapableBeanFactory专门实现了createBean方法,表示该IOC容器负责实例化Bean

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    @Override
    protected Object createBean(String beanName, 
                                BeanDefinition beanDefinition) throws BeansException  {
        return doCreateBean(beanName, beanDefinition);
    }

    /**
     * 根据BeanDefinition来创建一个bean对象
     * bean对象默认是单例的,所以创建完成后,需要将该bean注册进单例bean注册表
     * @return
     */
    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        Object bean = null;
        try {
            //为了简单,直接反射用无参构造器创建对象
            bean = beanClass.newInstance();
        } catch (Exception e) {
            throw new BeansException("实例化bean失败", e);
        }
        addSingleton(beanName, beanDefinition);
        return bean;
    }
}

DefaultListableBeanFactory则实现了getBeanDefinition方法,负责获取BeanDefinition

而想要获取BeanDefinition,又必须跟BeanDefinitionRegistry有关

故而DefaultListableBeanFactory是一个IOC容器,同时也是一个BeanDefinition注册表

public class DefaultListableBeanFactory 
    extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {

    //既然是BeanDefinition注册表,肯定要维护一个集合用来存储BeanDefinition
    private Map<String, BeanDefinition> map = new HashMap<>();

    //向BeanDefinition的注册表添加BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        //可以在注册前判断一下beanName是否重复
        map.put(beanName, beanDefinition);
    }

    @Override
    protected BeanDefinition getBeanDefinition(String beanName) {
        return map.get(beanName);
    }
}

作为BeanDefinitionRegistry和SingletonBeanRegistry的实现类,具备两者的能力。向bean容器中注册BeanDefintion后,使用bean时才会实例化,上面几个接口或类的关系如下

bean-definition-and-bean-definition-registry-1714450008898-1.png

至此,DefaultListableBeanFactory已经成了一个初具雏形可以使用的IOC容器

测试DefaultListableBeanFactory

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("狗剩", new BeanDefinition(Person.class));
Person p = (Person)beanFactory.getBean("狗剩");

assert p != null;
p.sayHello();

5 Bean的实例化策略

现在Bean是在AbstractAutowireCapableBeanFactory里直接被实例化的

针对Bean的实例化操作,也可以将其抽取出来抽象成实例化策略的接口InstantiationStrategy

InstantiationStrategy描述实例化Bean的规范

public interface InstantiationStrategy {
    //根据BeanDefinition实例化bean
    Object instantiate(BeanDefinition beanDefinition) throws BeansException;
}

两个实现类SimpleInstantiationStrategy、CglibSubclassingInstantiationStrategy

//bean的实例化策略实现-反射实例化Bean
class SimpleInstantiationStrategy implements InstantiationStrategy {
    @Override
    public Object instantiate(BeanDefinition beanDefinition) throws RuntimeException {
        Class beanClass = beanDefinition.getBeanClass();
        try {
            Constructor constructor = beanClass.getDeclaredConstructor();
            return constructor.newInstance();
        } catch (Exception e){
            throw new RuntimeException("实例化bean失败", e);
        }
    }
}
//bean的实例化策略实现-cglib动态实例化Bean
class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {

    @Override
    public Object instantiate(BeanDefinition beanDefinition) throws RuntimeException {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(beanDefinition.getBeanClass());
        enhancer.setCallback((MethodInterceptor) (obj, method, argsTemp, proxy) -> proxy.invokeSuper(obj,argsTemp));
        return enhancer.create();
    }
}

将实例化Bean操作抽象成实例化策略接口后,AbstractAutowireCapableBeanFactory改造如下

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
	//实例化策略,可以根据需求切换成不同的实现,这里写死为SimpleInstantiationStrategy实现
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) {
        return doCreateBean(beanName, beanDefinition);
    }

    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
        //实例化交给实例化策略组件后,就不需要这行代码了
        //Class beanClass = beanDefinition.getBeanClass();
        Object bean = null;
        try {
            //使用实例化策略来实例化Bean
            bean = createBeanInstance(beanDefinition);
        } catch (Exception e) {
            throw new RuntimeException("实例化bean失败", e);
        }
        addSingleton(beanName, beanDefinition);
        return bean;
    }
    
	//使用实例化策略,根据BeanDefinition来实例化Bean
    protected Object createBeanInstance(BeanDefinition beanDefinition) {
        return getInstantiationStrategy().instantiate(beanDefinition);
    }
    
    //实例化策略的get、set方法
    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }
    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}

这是典型的策略模式,对同一个目的,有不同的实现方法,将这些实现方法封装成不同的实现类,将来在程序中通过切换实现类,就能改变实例化Bean的策略

6 普通属性填充

一个Bean被实例化后,如何给Bean的属性赋值呢?

要给Bean的属性赋值,就要提前准备好属性名称和属性值

将属性名称和属性值封装成一个对象PropertyValue

public class PropertyValue {
    //属性名称
	private final String name;
    //属性值
	private final Object value;

	public PropertyValue(String name, Object value) {
		this.name = name;
		this.value = value;
	}
    
    public String getName() { return name; }
	public Object getValue() { return value; }
}

可能要给多个属性赋值,所以进一步封装成PropertyValues

public class PropertyValues {
	//存储多个PropertyValue
    private final List<PropertyValue> propertyValueList = new ArrayList<>();
	//添加PropertyValue
    public void addPropertyValue(PropertyValue pv) {
       propertyValueList.add(pv);
    }

    public PropertyValue[] getPropertyValues() {
       return propertyValueList.toArray(new PropertyValue[0]);
    }
    
	//根据属性名称获取将要被赋予的属性值
    public PropertyValue getPropertyValue(String propertyName) {
       for (PropertyValue pv : this.propertyValueList) {
            if (pv.getName().equals(propertyName)) {
                return pv;
            }
        }
        return null;
    }
}

我们知道,BeanDefinition描述了一个Bean的特征,其中就包括属性和属性值,所以BeanDefinition需要增加一个

PropertyValues类型属性

public class BeanDefinition {
    private Class beanClass;
    //新增的属性,用于描述Bean的属性和属性值
    private PropertyValues propertyValues;

    public BeanDefinition(Class beanClass) {
        this.beanClass = beanClass;
        this.propertyValues = new PropertyValues();
    }
    //新增一个构造器
    public BeanDefinition(Class beanClass, PropertyValues propertyValues) { 
        this.beanClass = beanClass;
        //确保propertyValues属性不为空
        this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
    }
    public Class getBeanClass() {return beanClass;}
    public void setBeanClass(Class beanClass) {this.beanClass = beanClass;}
    //新增PropertyValues的get、set方法
	public PropertyValues getPropertyValues() {return propertyValues;}
	public void setPropertyValues(PropertyValues propertyValues) {
		this.propertyValues = propertyValues;
	}

}

属性名称和属性值都准备好之后,就可以填充到Bean了

在哪一步进行填充呢?

在AbstractAutowireCapableBeanFactory里,实例化Bean之后,紧接着就是属性填充

AbstractAutowireCapableBeanFactory新增一个属性填充方法applyPropertyValues,改造如下

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) {
        return doCreateBean(beanName, beanDefinition);
    }

    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition);
            //实例化Bean之后,根据BeanDefinition给Bean填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new RuntimeException("初始化bean失败", e);
        }

        addSingleton(beanName, beanDefinition);
        return bean;
    }
    
    protected Object createBeanInstance(BeanDefinition beanDefinition) {
        return getInstantiationStrategy().instantiate(beanDefinition);
    }
    
    //属性填充,本质就是利用反射给Bean的属性赋值
    protected void applyPropertyValues(String beanName, Object bean, 
                                       BeanDefinition beanDefinition) {
		PropertyValues pvs = beanDefinition.getPropertyValues();
        try {
            for (PropertyValue pv : pvs.getPropertyValues()) {
                String name = pv.getName();
                Object value = pv.getValue();
                //通过反射给bean的属性赋值
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
            throw new BeansException("属性填充发生异常,在Bean:" + beanName, e);
        }
	}
    
    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }
    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}

至此代码还是很好理解

测试如下

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//准备属性名称和属性值
PropertyValues pvs = new PropertyValues();
pvs.addPropertyValue(new PropertyValue("name", "狗剩"));
//创建并注册BeanDefinition
BeanDefinition bd = new BeanDefinition(Person.class, pvs);
beanFactory.registerBeanDefinition("person", bd);

//获取Bean
Person person = (Person) beanFactory.getBean("person");
assert person != null;
assert "狗剩".equals(person.getName());
person.sayHello();

7 Bean属性填充

除了给Bean填充普通属性,还希望给Bean填充其他Bean类型的属性(来自IOC容器里的其他Bean)

封装一个BeanReference类用于描述所引用的其他Bean

public class BeanReference {
	//所引用的Bean的名称
	private final String beanName;
    
	public BeanReference(String beanName) {this.beanName = beanName;}
	public String getBeanName() {return beanName;}
}

然后改造AbstractAutowireCapableBeanFactory类,在applyPropertyValues方法里对属性类型进行判断,如果是BeanReference类型就根据BeanReference的beanName从容器中得到一个Bean来进行填充

比如beanA依赖beanB,则先实例化beanB,为了简单,这里没有考虑循环依赖

//节省篇幅,只演示了applyPropertyValues方法的代码,因为该类其他代码没有变
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
    PropertyValues pvs = beanDefinition.getPropertyValues();
    try {
        for (PropertyValue pv : pvs.getPropertyValues()) {
            String name = pv.getName();
            Object value = pv.getValue();

            //判断属性类型是否为BeanReference
            if (value instanceof BeanReference beanReference) {
                //先得到所依赖的Bean,如果该Bean没有实例化,则走一遍实例化流程
                //TODO 循环依赖未考虑
                value = getBean(beanReference.getBeanName());
            }

            //通过反射给bean的属性赋值
            BeanUtil.setFieldValue(bean, name, value);
        }
    } catch (Exception e) {
        throw new BeansException("属性填充发生异常,在Bean:" + beanName, e);
    }
}

测试如下

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//先注册IDCard的BeanDefinition
PropertyValues pvsForIdCard = new PropertyValues();
pvsForIdCard.addPropertyValue(new PropertyValue("idNumber", "11451419191810"));
BeanDefinition cardBd = new BeanDefinition(IDCard.class, pvsForIdCard);
beanFactory.registerBeanDefinition("card", cardBd);

//再注册Person的BeanDefinition
PropertyValues pvsForPerson = new PropertyValues();
pvsForPerson.addPropertyValue(new PropertyValue("name", "狗剩"));
pvsForPerson.addPropertyValue(new PropertyValue("idCard", new BeanReference("card")));
BeanDefinition personBd = new BeanDefinition(Person.class, pvsForPerson);
beanFactory.registerBeanDefinition("person", personBd);

//开始测试
Person person = (Person) beanFactory.getBean("person");
assert person != null;
assert "狗剩".equals(person.getName());
assert person.getIdCard() != null;
assert "11451419191810".equals(person.getIdCard().getIdNumber());
person.sayHello();

8 引入几个接口

到此为止,一切都很简洁,但是有没有感觉哪不对?

没错,是很简洁,不过简洁过头了,这里的简洁过头指两方面

  • IOC容器的功能太少
  • BeanFactory的继承层级太简陋

容器实现类直接实现BeanFactory,违反了Spring的设计哲学,Spring将功能点抽象成接口,每一层(个)接口实现的功能尽可能单一,大量的接口交织缠绕,共同协作构成了IOC容器的强大功能,所以IOC容器实现类不可能直接实现BeanFactory

在符合Spring的BeanFactory原本的层级和功能的基础上,仍然会做到最简洁,这里引入五个接口

  • HierarchicalBeanFactory

    提供了父子容器的支持和容器分层的能力

  • AutowireCapableBeanFactory

    代表了自动注入、创建和初始化 bean、应用BeanPostProcessors的能力

  • ListableBeanFactory

    提供了枚举容器内Bean的能力

  • ConfigurableBeanFactory

    提供了配置和管理 Spring 容器的能力,比如设置类型转换器、设置BeanPostProcessors、设置作用域、设置Bean的生命周期扩展

  • ConfigurableListableBeanFactory

    继承自AutowireCapableBeanFactoryListableBeanFactoryConfigurableBeanFactory,同时拥有它们的能力

有些接口的出现只是为了符合Spring的BeanFactory层级,本身的功能这里用不到,对这样的接口不提供抽象方法

首先是BeanFactory的三个子接口HierarchicalBeanFactory、AutowireCapableBeanFactory、ListableBeanFactory,他们直接继承了BeanFactory

//空接口
public interface HierarchicalBeanFactory extends BeanFactory {}
//空接口
public interface AutowireCapableBeanFactory extends BeanFactory {}
//枚举容器内Bean的接口
public interface ListableBeanFactory extends BeanFactory {
    //返回指定类型的所有实例
    <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
    //返回定义的所有bean的名称
    String[] getBeanDefinitionNames();
}

然后是ConfigurableBeanFactory,继承了HierarchicalBeanFactory和SingletonBeanRegistry,可以认为是一个单例Bean的注册表

public interface ConfigurableBeanFactory 
    extends HierarchicalBeanFactory, SingletonBeanRegistry {
}

接着是ConfigurableListableBeanFactory,提供了getBeanDefinition

public interface ConfigurableListableBeanFactory 
    extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
    //根据名称查找BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws BeansException;
}

关系图如下

classDiagram
direction TB
class BeanFactory {<< interface >>}
class HierarchicalBeanFactory {<< interface >>}
class AutowireCapableBeanFactory {<< interface >>}
class ListableBeanFactory {<< interface >>}
class ConfigurableBeanFactory {<< interface >>}
class ConfigurableListableBeanFactory {<< interface >>}
class SingletonBeanRegistry {<< interface >>}
BeanFactory <|-- HierarchicalBeanFactory
BeanFactory <|-- ListableBeanFactory
BeanFactory <|-- AutowireCapableBeanFactory
HierarchicalBeanFactory <|-- ConfigurableBeanFactory
SingletonBeanRegistry <|-- ConfigurableBeanFactory
AutowireCapableBeanFactory <|-- ConfigurableListableBeanFactory
ListableBeanFactory <|-- ConfigurableListableBeanFactory
ConfigurableBeanFactory <|-- ConfigurableListableBeanFactory

最后理一下各个接口和实现类的样子

BeanFactory,增加一个getBean的重载方法

public interface BeanFactory {
    //获取bean
    Object getBean(String name) throws BeansException;
    //根据名称和类型查找bean
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
}

BeanFactory三个直接子接口

public interface HierarchicalBeanFactory extends BeanFactory {}
public interface AutowireCapableBeanFactory extends BeanFactory {}
public interface ListableBeanFactory extends BeanFactory {
    <T> Map<String, T> getBeansOfType(Class<T> type) throws RuntimException;
    String[] getBeanDefinitionNames();
}

ConfigurableBeanFactory是HierarchicalBeanFactory的子接口

public interface ConfigurableBeanFactory 
extends HierarchicalBeanFactory, SingletonBeanRegistry {
}

ConfigurableListableBeanFactory,算是层级比较低的一个IOC接口

public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
    //根据名称查找BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws BeansException;
}

单例Bean注册表SingletonBeanRegistry,专门维护所有的单例Bean

public interface SingletonBeanRegistry {
    Object getSingleton(String beanName);
}

单例Bean注册表的实现类

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

AbstractBeanFactory,IOC容器实现类,同时也是一个单例Bean注册表,实现了getBean

//第一个实现类,将直接实现BeanFactory改成直接实现ConfigurableBeanFactory
public abstract class AbstractBeanFactory 
    extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
    @Override
    public Object getBean(String beanName) throws BeansException {
        //先从单例bean注册表中获取
        Object singleton = getSingleton(beanName);
        if (singleton != null) {
            return singleton;
        }

        //没有找到,则直接创建Bean返回
        BeanDefinition beanDefinition = getBeanDefinition(beanName);
        return createBean(beanName, beanDefinition);
    }

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

    /**
     * 负责实例化Bean,由子类实现
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

    /**
     * 负责获取BeanDefinition,由子类实现
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
}

AbstractAutowireCapableBeanFactory实现了实例化Bean的方法createBean

public abstract class AbstractAutowireCapableBeanFactory 
    extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    //实例化策略,可以根据需求切换成不同的实现,这里写死为SimpleInstantiationStrategy实现
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) 
        throws BeansException {
        return doCreateBean(beanName, beanDefinition);
    }

    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition);
            //实例化之后,紧接着就是属性填充
            applyPropertyValues(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("实例化bean失败", e);
        }
        //实例化完成后,将Bean注册进单例Bean注册表
        addSingleton(beanName, bean);
        return bean;
    }

    //使用实例化策略,根据BeanDefinition来实例化Bean
    protected Object createBeanInstance(BeanDefinition beanDefinition) {
        return getInstantiationStrategy().instantiation(beanDefinition);
    }

    //属性填充,本质就是利用反射给Bean的属性赋值
    protected void applyPropertyValues(String beanName, Object bean, 
                                       BeanDefinition beanDefinition) {
        PropertyValues pvs = beanDefinition.getPropertyValues();
        try {
            for (PropertyValue pv : pvs.getPropertyValues()) {
                String name = pv.getName();
                Object value = pv.getValue();

                //判断属性类型是否为BeanReference
                if (value instanceof BeanReference beanReference) {
                    //先得到所依赖的Bean,如果该Bean没有实例化,则走一遍实例化流程
                    //TODO 循环依赖未考虑
                    value = getBean(beanReference.getBeanName());
                }

                //通过反射给bean的属性赋值
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
            throw new BeansException("属性填充发生异常,在Bean:" + beanName, e);
        }
    }

    /**
     * 实例化策略的get、set方法
     * @return
     */
    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}

BeanDefinition的注册表,增加了几个抽象方法

public interface BeanDefinitionRegistry {

    //向注册表中注BeanDefinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    //根据名称查找BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    //是否包含指定名称的BeanDefinition
    boolean containsBeanDefinition(String beanName);

    //返回定义的所有bean的名称
    String[] getBeanDefinitionNames();
}

DefaultListableBeanFactory是目前功能最全的IOC容器实现类,同时也是一个BeanDefinition的注册表

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
       implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
	//存储所有BeanDefinition
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
	
    //下面四个方法实现了BeanDefinitionRegistry的抽象方法,本质就是操作集合beanDefinitionMap
    @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;
    }
    @Override
    public boolean containsBeanDefinition(String beanName) {
       return beanDefinitionMap.containsKey(beanName);
    }
    @Override
    public String[] getBeanDefinitionNames() {
       Set<String> beanNames = beanDefinitionMap.keySet();
       return beanNames.toArray(new String[beanNames.size()]);
    }
    
    //该方法实现了ListableBeanFactory的抽象方法,根据类型枚举所有Bean
    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
       Map<String, T> result = new HashMap<>();
       beanDefinitionMap.forEach((beanName, beanDefinition) -> {
          Class beanClass = beanDefinition.getBeanClass();
          //如果beanClass对应的对象能赋值给type对应的类
          if (type.isAssignableFrom(beanClass)) {
             T bean = (T) getBean(beanName);
             result.put(beanName, bean);
          }
       });
       return result;
    }
}

完整的继承关系图如下

xml-file-define-bean.png

注重实践哦~~~

9 资源的加载与访问

Spring中将资源的加载与访问抽象成了两个接口

资源的访问抽象成一个接口Resource

public interface Resource {
    //得到资源的流
	InputStream getInputStream() throws IOException;
}

这里写三个实现类,分别用于从类路径、磁盘和网络加载资源

类路径资源ClassPathResource

public class ClassPathResource implements Resource{
    private final String path;
	//创建实例时指定类路径
	public ClassPathResource(String path) {
		this.path = path;
	}
    
    @Override
	public InputStream getInputStream() throws IOException {
        //通过类加载器得到类路径下的资源
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(this.path);
		if (is == null) {
			throw new FileNotFoundException("类路径下不存在文件[" + path + "]");
		}
		return is;
	}
}

网络资源UrlResource

public class UrlResource implements Resource {
	private final URL url;
    //创建实例时指定url
    public UrlResource(URL url) {
        this.url = url;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        URLConnection conn = url.openConnection();
        try {
            return conn.getInputStream();
        } catch (IOException ex) {
            throw ex;
        }
    }
}

磁盘资源FileSystemResource

public class FileSystemResource implements Resource {

	private final String filePath;
	//创建实例时指定文件路径
	public FileSystemResource(String filePath) {
		this.filePath = filePath;
	}

	@Override
	public InputStream getInputStream() throws IOException {
		try {
			Path path = new File(this.filePath).toPath();
            //通过nio获取文件流
			return Files.newInputStream(path);
		} catch (NoSuchFileException ex) {
			throw new FileNotFoundException(ex.getMessage());
		}
	}
}

记得用完了关闭流哦

资源的加载抽象成了一个接口ResourceLoader,并依赖了资源访问组件

//资源加载器
public interface ResourceLoader {
	//资源访问,根据location不同会返回不同的Resource实现类
    Resource getResource(String location);
}

这里简单写了资源加载器的实现类DefaultResourceLoader,该类依赖了资源访问器的实现类

public class DefaultResourceLoader implements ResourceLoader {
    //Spring中,以"classpath:"开头的路径,就设定为类路径
    public static final String CLASSPATH_URL_PREFIX = "classpath:";
    
    @Override
	public Resource getResource(String location) {
        if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            //是类路径,则将前缀"classpath:"剔除了,使用ClassPathResource访问资源
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
        }
        else {
            try {
				//尝试当成url来处理
				URL url = new URL(location);
				return new UrlResource(url);
			} catch (MalformedURLException ex) {
				//当成文件系统下的资源处理
				return new FileSystemResource(location);
			}
        }
    }
}

使用者只需要使用DefaultResourceLoader和一个资源路径,就能得到Resource,进而得到目标资源的文件流,而不用关注资源的类型

简单测试一下

ResourceLoader loader = new DefaultResourceLoader();
//测试类路径资源
Resource resource = loader.getResource("classpath:hello.txt");
InputStream classIo = resource.getInputStream();
System.out.println("classpath下的资源:" + IoUtil.readUtf8(classIo));
IoUtil.close(classIo);

//测试文件系统下的资源
resource = loader.getResource("D:\\hello.txt");
InputStream fileSystemIo = resource.getInputStream();
System.out.println("磁盘上的资源:" + IoUtil.readUtf8(fileSystemIo));
IoUtil.close(fileSystemIo);

//测试网络资源
resource = loader.getResource("https://www.4399.com");
InputStream netIo = resource.getInputStream();
System.out.println("网络上的资源:" + IoUtil.readUtf8(netIo));
IoUtil.close(netIo);

10 XML中的Bean

Spring最早将Bean定义在XML文件里,通过解析XML文件加载所有BeanDefinition

需要一个组件提供加载BeanDefinition的能力,这就是接口BeanDefinitionReader,这句话透露出两个信息

  • BeanDefinitionReader必须依赖ResourceLoader,用于加载XML文件资源
  • BeanDefinitionReader必须依赖BeanDefinitionRegistry,用于将加载好的BeanDefinition添加进注册表

由此得出,BeanDefinitionReader长这样

//BeanDefinition加载器
public interface BeanDefinitionReader {
	//得到BeanDefinitionRegistry
	BeanDefinitionRegistry getRegistry();
	//得到ResourceLoader
	ResourceLoader getResourceLoader();
	//根据Resource加载BeanDefinition到BeanDefinitionRegistry
	void loadBeanDefinitions(Resource resource) throws BeansException;
	//根据字符串路径location加载BeanDefinition到BeanDefinitionRegistry
	void loadBeanDefinitions(String location) throws BeansException;
	//加载多个路径的BeanDefinition
	void loadBeanDefinitions(String[] locations) throws BeansException;
}

getRegistry、getResourceLoader这种方法肯定是通用的,所以添加一个抽象的实现类用于实现通用方法

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
	private final BeanDefinitionRegistry registry;
	private ResourceLoader resourceLoader;

    //构造方法
	protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, new DefaultResourceLoader());
	}
	public AbstractBeanDefinitionReader(BeanDefinitionRegistry registry, 
                                        ResourceLoader resourceLoader) {
		this.registry = registry;
		this.resourceLoader = resourceLoader;
	}
	//得到BeanDefinitionRegistry的通用方法
	@Override
	public BeanDefinitionRegistry getRegistry() {return registry;}
    //ResourceLoader的get、set方法
	@Override
	public ResourceLoader getResourceLoader() {return resourceLoader;}
    public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}
	//loadBeanDefinitions也是通用的,因为该方法并没有自己去加载BeanDefinition,而是调用了重载方法
	@Override
	public void loadBeanDefinitions(String[] locations) throws BeansException {
		for (String location : locations) {
			loadBeanDefinitions(location);
		}
	}
}

上面XML文件就是一个BeanDefinition源,另一个常见的源是被某些注解修饰的配置类,不同源对应不同实现类,这里介绍其中一个实现类:XmlBeanDefinitionReader,专门从XML文件里加载BeanDefinition

XmlBeanDefinitionReader的核心方法就是遍历指定XML文件的bean标签,将其内部property子标签封装成一个个PropertyValue对象,并将bean标签封装成BeanDefinition对象

核心方法如下,仅供参考

//将XML的标签bean设为常量,方便使用
public static final String BEAN_ELEMENT = "bean";
public static final String PROPERTY_ELEMENT = "property";
public static final String ID_ATTRIBUTE = "id";
public static final String NAME_ATTRIBUTE = "name";
public static final String CLASS_ATTRIBUTE = "class";
public static final String VALUE_ATTRIBUTE = "value";
public static final String REF_ATTRIBUTE = "ref";

protected void doLoadBeanDefinitions(InputStream inputStream) {
    	//hutool解析XML的工具类
		Document document = XmlUtil.readXML(inputStream);
		Element root = document.getDocumentElement();
		NodeList childNodes = root.getChildNodes();
    	//变量bean标签
		for (int i = 0; i < childNodes.getLength(); i++) {
			if (childNodes.item(i) instanceof Element) {
                //得到bean标签
				String beanNode = childNodes.item(i).getNodeName();
				if (BEAN_ELEMENT.equals(beanNode)) {
					//解析bean标签
					Element bean = (Element) childNodes.item(i);
					String id = bean.getAttribute(ID_ATTRIBUTE);
					String name = bean.getAttribute(NAME_ATTRIBUTE);
					String className = bean.getAttribute(CLASS_ATTRIBUTE);

					Class<?> clazz = null;
					try {
						clazz = Class.forName(className);
					} catch (ClassNotFoundException e) {
						throw new BeansException("找不到类: [" + className + "]");
					}
					//id优先于name
					String beanName = StrUtil.isNotEmpty(id) ? id : name;
					if (StrUtil.isEmpty(beanName)) {
						//如果id和name都为空,将类名的第一个字母转为小写后作为bean的名称
						beanName = StrUtil.lowerFirst(clazz.getSimpleName());
					}

					BeanDefinition beanDefinition = new BeanDefinition(clazz);
                    //遍历bean标签里的property标签
					for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
						if (bean.getChildNodes().item(j) instanceof Element) {
							String propertyNode = bean.getChildNodes().item(j).getNodeName();
							if (PROPERTY_ELEMENT.equals(propertyNode)) {
								//解析property标签
								Element property = (Element) bean.getChildNodes().item(j);
								String nameAttribute = property.getAttribute(NAME_ATTRIBUTE);
								String valueAttribute = property.getAttribute(VALUE_ATTRIBUTE);
								String refAttribute = property.getAttribute(REF_ATTRIBUTE);

								if (StrUtil.isEmpty(nameAttribute)) {
									throw new BeansException("name属性不能为空");
								}
								Object value = valueAttribute;
								if (StrUtil.isNotEmpty(refAttribute)) {
									value = new BeanReference(refAttribute);
								}
                                //封装成PropertyValue,并添加到BeanDefinition里
								PropertyValue propertyValue = new 
                                    PropertyValue(nameAttribute, value);
								beanDefinition
                                    .getPropertyValues()
                                	.addPropertyValue(propertyValue);
							}
						}
					}
					if (getRegistry().containsBeanDefinition(beanName)) {
						//beanName不能重名
						throw new BeansException("不允许重复beanName[" + beanName + "]");
					}
					//注册BeanDefinition
					getRegistry().registerBeanDefinition(beanName, beanDefinition);
				}
			}
		}
	}

XmlBeanDefinitionReader完整代码如下

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {super(registry);}
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, 
                                   ResourceLoader resourceLoader) {
       super(registry, resourceLoader);
    }

    @Override
    public void loadBeanDefinitions(String location) throws BeansException {
       ResourceLoader resourceLoader = getResourceLoader();
       Resource resource = resourceLoader.getResource(location);
       loadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(Resource resource) throws BeansException {
       try(InputStream inputStream = resource.getInputStream()) {
            doLoadBeanDefinitions(inputStream);
        } catch (IOException ex) {
            throw new BeansException("解析XML异常:" + resource, ex);
        }
    }

    protected void doLoadBeanDefinitions(InputStream inputStream){
        //doLoadBeanDefinitions方法如上所示
    }
}

解析方式很多,最后目的只有一个,就是从BeanDefinition源加载BeanDefinition然后注册进BeanDefinitionRegistry

测试一下,先准备一个XML文件,为了简洁没有添加DTD约束

<!--spring.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="card" class="org.springframework.test.bean.IDCard">
        <property name="idNumber" value="114514"></property>
    </bean>
    <bean id="person" class="org.springframework.test.bean.Person">
        <property name="name" value="狗剩"></property>
        <property name="idCard" ref="card"></property>
    </bean>
</beans>

测试代码如下

//DefaultListableBeanFactory也是一个BeanDefinition注册表
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:spring.xml");

//加载完毕后,看beanFactory内Bean的情况
assert beanFactory.getBeanDefinitionNames().length > 0;
for (String name : beanFactory.getBeanDefinitionNames()) {
    Object bean = beanFactory.getBean(name);
    System.out.println(bean);
}

11 BeanFactoryPostProcessor

Spring中有很多特殊类型Bean,所谓特殊,就是实现了某些接口的Bean,在实例化过程中会挨个判断Bean有没有实现这些接口,如果实现了就回调其接口方法

BeanFactoryPostProcessor就是这种特殊类型的Bean,翻译为BeanFactory后处理器

有些IOC容器拥有refresh刷新方法,就是根据已有的BeanDefinition初始化所有bean,流程大致如下

  1. 回调BeanFactoryPostProcessor,对现有的BeanDefinition进行修改
  2. 遍历所有BeanDefinition挨个实例化

这里引入一个新接口BeanFactoryPostProcessor用于在BeanDefintion加载完毕后,再对其进行增删改

public interface BeanFactoryPostProcessor {
    //在所有BeanDefinition加载完成后,但在bean实例化之前,提供修改BeanDefinition属性值的机制
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
        throws BeansException;
}

实现了BeanFactoryPostProcessor接口的就是一个BeanFactory后处理器,属于业务层面

下面是一个自定义BeanFactory后处理器

//判断容器内有没有一个Person类型的BeanDefinition,有则将其name属性写死为张三
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //这就是为什么ConfigurableListableBeanFactory也有个getBeanDefinition方法,方便使用
        for (String name : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition bd = beanFactory.getBeanDefinition(name);
            if (Person.class.isAssignableFrom(bd.getBeanClass())) {
                PropertyValue pv = new PropertyValue("name", "张三");
                bd.getPropertyValues().addPropertyValue(pv);
            }
        }
    }
}

这有什么用呢?用处可大了去了,比如扫描指定路径下的所有类文件,然后判断其是否加了某些注解并根据注解将其解析成BeanDefinition进行注册什么的.....

测试,BeanFactory后处理器应该交给Spring管理,XML文件增加如下标签

<!--spring.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!--增加一个BeanFactory后处理器,Person和IdCard不做改变,所以这里省略了-->
    <bean id="bfpp" class="org.springframework.test.common.MyBeanFactoryPostProcessor">
    </bean>
</beans>

测试代码如下

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:spring.xml");

assert beanFactory.getBeanDefinitionNames().length > 0;
//BeanDefinition加载完毕后,应用BeanFactory后处理器,也就是找到并回调所有BeanFactory后处理器
for (String name : beanFactory.getBeanDefinitionNames()) {
    BeanDefinition bd = beanFactory.getBeanDefinition(name);
    //如果某个BeanDefinition是BeanFactoryPostProcessor类型
    if (BeanFactoryPostProcessor.class.isAssignableFrom(bd.getBeanClass())) {
        BeanFactoryPostProcessor bfpp = 
            beanFactory.getBean(name, BeanFactoryPostProcessor.class);
        bfpp.postProcessBeanFactory(beanFactory);
    }
}

//应用BeanFactory后处理器完毕后,查询容器内Bean的情况,看person的name有没有被改成"张三"
for (String name : beanFactory.getBeanDefinitionNames()) {
    Object bean = beanFactory.getBean(name);
    System.out.println(bean);
}

Spring的常用注解@Configuration,@ComponentScan,@Bean,@Component,@Import,@ImportResource就是由一个BeanFactory后处理器ConfigurationClassPostProcessor负责解析的

12 BeanPostProcessor

Bean后处理器,也是一种特殊类型的Bean,实现自BeanPostProcessor接口

Bean的实例化过程分为很多步骤,也就是所谓Bean的生命周期,比如构造、依赖注入、前初始化、初始化、后初始化、销毁前、销毁

生命周期的代码体现就是在不同阶段调用不同的回调函数,在这些回调函数中可以修改Bean,或者替换Bean(这是AOP的关键,用带有增强代码的代理Bean替换原始Bean不就可以实现增强了吗)

引入BeanPostProcessor,通过继承BeanPostProcessor扩展生命周期的不同阶段,这里简单演示前后初始化阶段

public interface BeanPostProcessor {
    //在bean执行初始化方法之前执行此方法
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //在bean执行初始化方法之后执行此方法
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

自定义一个Bean后处理器,属于业务层面

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean,
                                                  String beanName) throws BeansException {
        System.out.println("前初始化...");
        //这里返回的Bean会替换原始Bean
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean,
                                                 String beanName) throws BeansException {
        System.out.println("后初始化...");
        //这里返回的Bean会替换原始Bean
        return bean;
    }
}

前面说过ConfigurableBeanFactory的作用之一是设置Bean生命周期扩展,所以增加addBeanPostProcessor,代码简单,这里省略了

Bean后处理器保存在其实现类AbstractBeanFactory中,AbstractBeanFactory原本的代码不动,增加下面的代码

public abstract class AbstractBeanFactory 
    extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
	//维护所有的BeanPostProcessor
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
    
    //添加BeanPostProcessor
    //该方法实现自AbstractBeanFactory接口的抽象方法
    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
       this.beanPostProcessors.remove(beanPostProcessor);
       this.beanPostProcessors.add(beanPostProcessor);
    }
    //得到BeanPostProcessor
    public List<BeanPostProcessor> getBeanPostProcessors() {
       return this.beanPostProcessors;
    }
}

BeanPostProcessor有了,在哪里使用BeanPostProcessor呢?当然是在createBean方法中

在AutowireCapableBeanFactory接口中增加两个抽象方法用于表示前初始化、后初始化

public interface AutowireCapableBeanFactory extends BeanFactory {
	//执行BeanPostProcessors的postProcessBeforeInitialization
	Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, 
                                                       String beanName) throws BeansException;
	//执行BeanPostProcessors的postProcessAfterInitialization
	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, 
                                                      String beanName) throws BeansException;
}

下面演示的只是AbstractAutowireCapableBeanFactory中修改或者新增的代码,该类其他代码原封不动

public abstract class AbstractAutowireCapableBeanFactory 
    extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    //在属性填充后,调用initializeBean进行前后初始化以及初始化的操作
    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
       Object bean = null;
       try {
          bean = createBeanInstance(beanDefinition);
          applyPropertyValues(beanName, bean, beanDefinition);
          //属性填充后,紧接着就是前初始化、初始化、后初始化
          bean = initializeBean(beanName, bean, beanDefinition);
       } catch (Exception e) {
          throw new BeansException("Instantiation of bean failed", e);
       }
       addSingleton(beanName, bean);
       return bean;
    }

	//Bean的初始化相关操作
    protected Object initializeBean(String beanName, 
                                    Object bean, BeanDefinition beanDefinition) {
        //1.执行前初始化
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        //2.TODO 执行初始化
        invokeInitMethods(beanName, wrappedBean, beanDefinition);
        //3.执行后初始化
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        //返回经过初始化流程的Bean,此时的Bean跟原来的Bean可能不是同一个对象
        return wrappedBean;
    }

    //前初始化方法
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(
        Object existingBean, String beanName) throws BeansException {
        //由于前后初始化的逻辑是固定的,只是调用的BeanPostProcessors方法不一样
        //所以这里把固定的代码抽取成applyBeanPostProcessors,将变化的代码抽取成函数对象传给这个方法
        return applyBeanPostProcessors(existingBean, beanName,
               processor -> processor.postProcessBeforeInitialization(existingBean, beanName));
    }
    
    //Bean的初始化方法
    protected void invokeInitMethods(String beanName, 
                                     Object bean, BeanDefinition beanDefinition) {
       //TODO 后面会实现
       System.out.println("执行bean[" + beanName + "]的初始化方法");
    }
    
    //后初始化方法
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(
        Object existingBean, String beanName) throws BeansException {
        return applyBeanPostProcessors(existingBean, beanName,
               processor -> processor.postProcessAfterInitialization(existingBean, beanName));
    }
    
    private Object applyBeanPostProcessors(
        Object existingBean, String beanName, Function<BeanPostProcessor, Object> bf) {
        Object result = existingBean;
        //得到所有BeanPostProcessor,然后依次调用postProcessAfterInitialization
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = bf.apply(processor);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
}

测试一下

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:spring.xml");

//手动注册Bean后处理器
beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());

//实例化person,发现card、person的初始化流程依次执行
Person person = beanFactory.getBean("person", Person.class);
assert person != null;
person.sayHello();

Spring提供了几个BeanPostProcessor

  • AutowiredAnnotationBeanPostProcessor :负责解析@Autowired,@Value
  • CommonAnnotationBeanPostProcessor :负责解析@Resource,@PostConstruct,@PreDestroy

BeanFactoryPostProcessor和BeanPostProcessor是典型的模板方法设计模式

到此为止,从Bean的角度看,其生命周期如下

graph TB;
    A(从源加载BeanDefinition并注册进容器);
    A --> B(应用BeanFactoryPostProcessor修改BeanDefinition);
    B --> C(开始实例化Bean-构造Bean);
    C --> D(属性填充)
    D --> E(前初始化)
    E --> F(初始化)
    F --> G(后初始化)
    G --> H(得到成品Bean并使用)
    

13 ApplicationContext

ApplicationContext是一个IOC容器的接口,翻译为应用上下文容器,较之BeanFactory功能更全、使用更便捷,面向Spring的使用者,而BeanFactory则更多在Spring框架内部被使用

ApplicationContext组合了BeanFactory,拥有BeanFactory全部功能,组合的好处是不用自己实现一遍已有功能,而且ApplicationContext作为一个容器,也继承了BeanFactory

此外,ApplicationContext的额外功能可以总结如下:

  • BeanFactoryPostProcessor和BeanPostProcessor的自动识别,不用手动编码注册到容器
  • 根据BeanDefinition实例化全部单例Bean(refresh刷新容器)
  • 事件发布和监听
  • 资源加载
  • 国际化支持

这里ApplicationContext简单继承几个已有的接口

//应用上下文容器的顶层接口
public interface ApplicationContext 
    extends ListableBeanFactory, HierarchicalBeanFactory, ResourceLoader {
}

应用上下文容器拥有的一个最重要的功能就是刷新容器,定义一个拥有refresh抽象方法的子接口

//可配置的ApplicationContext,拥有refresh刷新方法
public interface ConfigurableApplicationContext extends ApplicationContext {
    /**
     * 刷新容器,目前刷新流程如下
     *  1.创建BeanFactory
     *  2.回调BeanFactoryPostProcessor
     *  3.注册BeanPostProcessor
     *  4.实例化全部单例Bean
     */
    void refresh() throws BeanException;
}

同时给ConfigurableListableBeanFactory增加方法以配合refresh,最新代码如下

public interface ConfigurableListableBeanFactory 
    extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
    //根据名称查找BeanDefinition,找不到则抛出异常
    BeanDefinition getBeanDefinition(String beanName) throws BeansException;
    //提前实例化所有单例实例
    void preInstantiateSingletons() throws BeansException;
    //对应添加Bean后处理器的方法,方便通过ConfigurableListableBeanFactory使用
    void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
}

在DefaultListableBeanFactory实现preInstantiateSingletons方法

@Override
public void preInstantiateSingletons() throws BeansException {
    beanDefinitionMap.keySet().forEach(this::getBean);
}

实现类AbstractApplicationContext负责实现refresh方法,并且继承DefaultResourceLoader拥有资源加载能力

应用上下文容器持有一个BeanFactory,方便使用其功能,为了解耦合,跟BeanFactory相关的方法在其子类维护

同时AbstractApplicationContext也是ListableBeanFactory实现类,需要实现其几个抽象方法,此时持有BeanFactory的好处就出来了,在实现方法里调用BeanFactory对应的方法

public abstract class AbstractApplicationContext 
    extends DefaultResourceLoader implements ConfigurableApplicationContext{
    //刷新容器
    @Override
	public void refresh() throws BeansException {
		//创建BeanFactory,并从源加载BeanDefinition
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		//在bean实例化之前,执行BeanFactoryPostProcessor
		invokeBeanFactoryPostProcessors(beanFactory);
		//BeanPostProcessor需要提前与其他bean实例化之前注册
		registerBeanPostProcessors(beanFactory);
		//提前实例化单例bean
		beanFactory.preInstantiateSingletons();
	}
    
    //应用BeanFactoryPostProcessors
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory bf) {
        //得到所有BeanFactoryPostProcessor类型的Bean,然后挨个回调
		Map<String, BeanFactoryPostProcessor> bfppMap = bf
            .getBeansOfType(BeanFactoryPostProcessor.class);
		for (BeanFactoryPostProcessor bfpp : bfppMap.values()) {
			bfpp.postProcessBeanFactory(bf);
		}
	}
    
    //注册BeanPostProcessor
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory bf) {
        //得到所有BeanPostProcessor类型的Bean,然后挨个添加到BeanFactory
		Map<String, BeanPostProcessor> bppMap = bf.getBeansOfType(BeanPostProcessor.class);
		for (BeanPostProcessor bpp : bppMap.values()) {
			bf.addBeanPostProcessor(bpp);
		}
	}
    
    /**
     * 下面四个方法是ListableBeanFactory的实现方法
     */
    @Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return getBeanFactory().getBean(name, requiredType);
	}
	@Override
	public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
		return getBeanFactory().getBeansOfType(type);
	}
	@Override
	public Object getBean(String name) throws BeansException {
		return getBeanFactory().getBean(name);
	}
	@Override
	public String[] getBeanDefinitionNames() {
		return getBeanFactory().getBeanDefinitionNames();
	}
    
    /**
     * 下面两个抽象方法跟BeanFactory有关,有专门的子类来维护
     */
    //创建BeanFactory,并加载BeanDefinition
    protected abstract void refreshBeanFactory() throws BeansException;
    //得到应用上下文容器持有的BeanFactory
    public abstract ConfigurableListableBeanFactory getBeanFactory();
}

子类AbstractRefreshableApplicationContext专门维护跟BeanFactory有关的代码

同样,跟资源加载的相关代码由子类来维护,不同的源有不同的子类

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{
    //应用上下文持有BeanFactory
    private DefaultListableBeanFactory beanFactory;
    
    //实现父类的抽象方法
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        //创建BeanFactory实例
		beanFactory = createBeanFactory();
        //从源加载BeanDefinition
		loadBeanDefinitions(beanFactory);
	}
    //实现父类的抽象方法
    @Override
    public DefaultListableBeanFactory getBeanFactory() {return beanFactory;}
    
    //创建BeanFactory实例
    protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory();
	}
    
    //该抽象方法跟资源加载有关,放在子类实现
    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 
        										throws BeansException;
}

抽象XML的应用上下文容器,专门处理XML资源加载,XML的路径信息在其子类中维护

public abstract class AbstractXmlApplicationContext
    extends AbstractRefreshableApplicationContext {

    //从XML文件加载BeanDefinition到BeanFactory
    protected void loadBeanDefinitions(DefaultListableBeanFactory bf) {
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf, this);
        //得到XML文件路径
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

    //子类维护XML文件的路径信息
    protected abstract String[] getConfigLocations();
}

最后就是维护XML文件路径的应用上下文容器ClassPathXmlApplicationContext,也是我们直接使用的容器,通过传入XML的类路径信息来创建一个容器

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

    private String[] configLocations;

    //构造方法的重载,从一个xml文件加载BeanDefinition,并且自动刷新上下文
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
       this(new String[]{configLocation});
    }

    //构造方法的重载,从若干个xml文件加载BeanDefinition,并且自动刷新上下文
    public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
       this.configLocations = configLocations;
       refresh();
    }

    //调用构造方法一定会传入路径信息,这里返回这个路径信息
    protected String[] getConfigLocations() {
       return this.configLocations;
    }
}

简简单单测试一下ClassPathXmlApplicationContext

ClassPathXmlApplicationContext context 
    = new ClassPathXmlApplicationContext("classpath:spring.xml");
Person person = context.getBean("person", Person.class);
assert person != null;
person.sayHello();

我们初学Spring时,使用的就是上面的代码作为入门程序

现在一个简陋但功能齐全的Spring容器就实现了,实现Spring的强大功能无非就是进行在此基础上不断迭代升级而且

14 Bean的初始化和销毁

前面留了一个TODO,就是并没有实现Bean的初始化方法,销毁方法和初始化方法也是一样的

Spring中Bean的初始化和销毁方法有下面四种定义方法

  1. XML中指定init-method和destroy-method
  2. Bean继承InitializingBean和DisposableBean接口
  3. 方法上加注解PostConstruct和PreDestroy
  4. 配置类中使用@Bean指定初始化方法和销毁方法

本节只实现前面两种

在BeanDefinition中增加两个属性用于表示初始化方法和销毁方法

public class BeanDefinition {
    //Bean的class对象
    private Class beanClass;
    //Bean需要被注入的属性和值
    private PropertyValues propertyValues;
    //初始化和销毁
    private String initMethodName;
    private String destroyMethodName;

    public BeanDefinition(Class beanClass) {
        this.beanClass = beanClass;
        this.propertyValues = new PropertyValues();
    }
    public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
        this.beanClass = beanClass;
        //确保propertyValues属性不可能为空
        this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
    }
    
	//省略了get、set方法
    //.....
}

增加一个Student类用于测试初始化方法和销毁方法

public class Student {
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    public void initMethod() {
        System.out.println("初始化方法...");
    }
    public void destroyMethod() {
        System.out.println("销毁方法...");
    }
}

对于第一种,需要XML文件给Bean标签添加init-method和destroy-method属性,对应着BeanDefinition增加的两个成员属性initMethodName、destroyMethodName

<!--init-destroy-bean.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="student" class="org.springframework.test.bean.Student"
          init-method="initMethod"
          destroy-method="destroyMethod">
        <property name="name" value="小红同学"></property>
    </bean>
</beans>

将来在XmlBeanDefinitionReader#doLoadBeanDefinitions中解析XML成BeanDefinition时,获取这两个标签属性的值然后赋值给BeanDefinition对应的成员属性,代码很简单,这里略过

对于第二种,需要增加两个接口分别表示初始化接口和销毁接口

初始化接口,将来初始化Bean时回调这个接口的抽象方法即可

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

销毁接口

public interface DisposableBean {
    void destroy() throws Exception;
}

Student类实现这两个接口

public class Student implements InitializingBean, DisposableBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }
    public void initMethod() {
        System.out.println("初始化方法...");
    }
    public void destroyMethod() {
        System.out.println("销毁方法...");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
		System.out.println("来自接口初始化方法...");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("来自接口销毁方法...");
    }
}

对于销毁,流程则稍微复杂点,首先在ConfigurableBeanFactory定义销毁所有单例Bean的方法

public interface ConfigurableBeanFactory 
    extends HierarchicalBeanFactory, SingletonBeanRegistry {
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
    //销毁单例Bean,这里定义只是因为作为一个单例Bean注册表需要有这个方法,但是并没有类实现该方法
    void destroySingletons();
}

然后再DefaultSingletonBeanRegistry中增加属性disposableBeans保存拥有销毁方法的单例bean

//该类增加如下代码,其他代码原封不动
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    //保存拥有销毁方法的单例Bean
    private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
    
    //注册拥有销毁方法的单例Bean
    public void registerDisposableBean(String beanName, DisposableBean bean) {
		disposableBeans.put(beanName, bean);
	}
    
    //销毁拥有销毁方法的单例Bean前,回调一次其销毁方法
    //该方法并不是实现自ConfigurableBeanFactory
    public void destroySingletons() {
		ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
		for (String beanName : beanNames) {
			DisposableBean disposableBean = disposableBeans.remove(beanName);
			try {
				disposableBean.destroy();
			} catch (Exception e) {
				throw new BeansException("销毁Bean[" + beanName + "]失败", e);
			}
		}
	}
}

DisposableBeanAdapter类来封装拥有销毁方法的Bean

public class DisposableBeanAdapter implements DisposableBean {
    //Bean的实例
    private final Object bean;
	//Bean名称
    private final String beanName;
	//销毁方法名称
    private final String destroyMethodName;

    public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) {
       this.bean = bean;
       this.beanName = beanName;
       this.destroyMethodName = beanDefinition.getDestroyMethodName();
    }

    @Override
    public void destroy() throws Exception {
       //如果是实现DisposableBean接口的话,直接执行销毁方法
       if (bean instanceof DisposableBean) {
          ((DisposableBean) bean).destroy();
       }

       //如果是在XML中定义的话,则通过方法名称反射调用销毁方法
       //该if是避免继承了DisposableBean,同时XML中定义的destroy-method也叫destroy,销毁方法执行两次的情况
       if (StrUtil.isNotEmpty(destroyMethodName) 
           && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
          //执行自定义方法
          Method destroyMethod = ClassUtil.getPublicMethod(bean.getClass(), destroyMethodName);
          if (destroyMethod == null) {
             throw new BeansException("Bean[" + bean + "]中没有销毁方法:" + destroyMethodName);
          }
          destroyMethod.invoke(bean);
       }
    }
}

向虚拟机注册一个钩子,确保在虚拟机关闭前,会回调这些Bean的销毁方法

然后在AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary中判断某个Bean是否有销毁方法,有则注册到disposableBeans中

而对于初始化则相对简单,AbstractAutowireCapableBeanFactory增加的代码如下

public abstract class AbstractAutowireCapableBeanFactory 
    extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    
    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
		Object bean = null;
		try {
			bean = createBeanInstance(beanDefinition);
			applyPropertyValues(beanName, bean, beanDefinition);
			initializeBean(beanName, bean, beanDefinition);
		} catch (Exception e) {
			throw new BeansException("Instantiation of bean failed", e);
		}
		//将成品Bean注册到单例Bean注册表之前,先注册拥有销毁方法的Bean
		registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
		addSingleton(beanName, bean);
		return bean;
	}
    
    //判断该Bean是否有必要注册到disposableBeans
    protected void registerDisposableBeanIfNecessary(
        String beanName, Object bean, BeanDefinition beanDefinition) {
        //得到BeanDefinition中的销毁方法名称
        String destroyMethodName = beanDefinition.getDestroyMethodName();
        //判断该Bean是否实现了DisposableBean接口,或者BeanDefinition中的销毁方法名称是否不为空
		if (bean instanceof DisposableBean || StrUtil.isNotEmpty(destroyMethodName)) {
            DisposableBeanAdapter a = new DisposableBeanAdapter(bean,beanName,beanDefinition);
			registerDisposableBean(beanName, a);
		}
	}
    
    //执行前后初始化以及初始化
    protected Object initializeBean(String beanName, Object bean, 
                                    BeanDefinition beanDefinition) {
        //1.执行前初始化
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        //2.执行初始化
        try {
            invokeInitMethods(beanName, wrappedBean, beanDefinition);
        } catch (Exception ex) {
            throw new BeansException("初始化Bean:[" + beanName + "] 失败", ex);
        }
        //3.执行后初始化
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        return wrappedBean;
    }
    
    //初始化阶段
    protected void invokeInitMethods(String beanName, Object bean, 
                                     BeanDefinition beanDefinition) throws Exception {
		//如果是继承了接口,则直接回调相关方法
        if (bean instanceof InitializingBean) {
			((InitializingBean) bean).afterPropertiesSet();
		}
        
        //如果在BeanDefinition定义了方法,则反射回调调用其初始化方法
		//反射代码略.....
	}
}

在实例化Bean的初始化阶段,其定义的初始化方法就会被回调了,但是并不会销毁方法

那么什么时候回调销毁方法呢?

在关闭容器或者关闭虚拟机时,会调销毁方法,AbstractApplicationContext增加如下代码

public abstract class AbstractApplicationContext 
    extends DefaultResourceLoader implements ConfigurableApplicationContext {
    //关闭容器
    public void close() {
		doClose();
	}
    
    //向虚拟机注册钩子,虚拟机关闭时回调该指定方法
    //需要调用该方法,才会注册给虚拟机
    public void registerShutdownHook() {
        //虚拟机关闭时启动该线程执行任务
		Thread shutdownHook = new Thread() {public void run() {doClose();}};
        //将任务线程注册给虚拟机
		Runtime.getRuntime().addShutdownHook(shutdownHook);
	}
    
    protected void doClose() {destroyBeans();}
    //真正执行销毁
    protected void destroyBeans() {
        //这行代码有点门道
        getBeanFactory().destroySingletons();
    }
}

测试一下

ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath:init-destroy-bean.xml");
applicationContext.close();
//或者applicationContext.registerShutdownHook();

此时,Bean的生命周期如下

graph TB;
    A(从源加载BeanDefinition并注册进容器);
    A --> B(应用BeanFactoryPostProcessor修改BeanDefinition);
    B --> C(开始实例化Bean-构造Bean);
    C --> D(属性填充)
    D --> E(前初始化)
    E --> F(初始化->InitializingBean->init-method)
    F --> G(后初始化)
    G --> H(得到成品Bean并使用)
    H --> I(销毁->DisposableBean->destroy-method)

15 Aware接口

前面说过,Spring定义了一些接口,实例化Bean时一旦发现Bean实现了这些接口就会回调对应方法

其中就包括Aware系列接口,这种接口的名称以Aware结尾

Aware的意思是感知、意识到,比如BeanFactoryAware就表示能够感知到BeanFactory,也就是其实现类可以直接得到BeanFactory容器

定义一个Aware接口作为所有Aware系列接口的父接口

public interface Aware {}

这里定义两个子接口,分别表示感知到BeanFactory、感知到ApplicationContext

BeanFactoryAware

public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

ApplicationContextAware

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

BeanFactoryAware的调用比较简单,因为Bean就是在BeanFactory实现类中被实例化的,在初始化时判断Bean是否实现了BeanFactoryAware,实现了就回调setBeanFactory方法,参数是this

public abstract class AbstractAutowireCapableBeanFactory 
    extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    
    //initializeBean方法前三行增加代码
    protected Object initializeBean(String beanName, Object bean, 
                                    BeanDefinition beanDefinition) {
        //增加下面这个if判断
        //判断是否为BeanFactoryAware实现类
		if (bean instanceof BeanFactoryAware aware) {
            aware.setBeanFactory(this);
        }
		//....其他代码原封不动
	}
    
}

ApplicationContextAware的调用就稍微复杂点,因为BeanFactory 并未持有ApplicationContext

注册BeanPostProcessor的操作是在上下文容器的refresh中进行的,因此可以将ApplicationContextAware的回调放在一个BeanPostProcessor中,然后在refresh方法中注册这个BeanPostProcessor,将this传递给进去

ApplicationContextAwareProcessor就是负责调用ApplicationContextAware的Bean后处理器

public class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ApplicationContext applicationContext;
	//构造时将ApplicationContext传递进来
    public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
       this.applicationContext = applicationContext;
    }

    //前初始化阶段,进行ApplicationContextAware的回调
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
        throws BeansException {
       //如果该Bean是ApplicationContextAware实现类,则回调setApplicationContext方法
       if (bean instanceof ApplicationContextAware aware) {
            aware.setApplicationContext(applicationContext);
        }
       return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) 
        throws BeansException {
       return bean;
    }
}

然后在ApplicationContext的refresh方法中注册这个BeanPostProcessor

public abstract class AbstractApplicationContext 
    extends DefaultResourceLoader implements ConfigurableApplicationContext {
    
    @Override
	public void refresh() throws BeansException {

		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();

		//注册ApplicationContextAwareProcessor,跟其他PostProcessors区分开
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

		invokeBeanFactoryPostProcessors(beanFactory);
		registerBeanPostProcessors(beanFactory);
		beanFactory.preInstantiateSingletons();
	}
    
}

将来在Bean的前初始化阶段,就能调用到ApplicationContextAwareProcessor,从而调用到ApplicationContextAware

此时Bean的生命周期如下

graph TB;
    A(从源加载BeanDefinition并注册进容器);
    A --> B(应用BeanFactoryPostProcessor修改BeanDefinition);
    B --> C(开始实例化Bean-构造Bean);
    C --> D(属性填充)
    D --> X(BeanFactoryAware)
    X --> E(前初始化#ApplicationContextAware)
    E --> F(初始化->InitializingBean->init-method)
    F --> G(后初始化)
    G --> H(得到成品Bean并使用)
    H --> I(销毁->DisposableBean->destroy-method)

16 作用域之Prototype

前面的Bean作用域Scope都默认为单例singleton,也就是getBean时只实例化一次,后续再getBean得到的都是同一个Bean,因此需要保存起来方便后续使用

而一个常见的Scope——prototype,每次getBean得到的都是不同的Bean,也就是说每次getBean都会走一遍Bean的生命周期流程,因此这种Bean不需要保存起来,而且这种Bean也不需要走销毁流程,不用了自然被GC回收

在BeanDefinition中增加几个属性用来表示Scope

public class BeanDefinition {
	//增加两个常量
    public static String SCOPE_SINGLETON = "singleton";
    public static String SCOPE_PROTOTYPE = "prototype";

    private Class beanClass;

    private PropertyValues propertyValues;

    private String initMethodName;

    private String destroyMethodName;

    private String scope = SCOPE_SINGLETON;
	//该BeanDefinition的作用域是否为singleton
    private boolean singleton = true;
	//该BeanDefinition的作用域是否为prototype
    private boolean prototype = false;

    public BeanDefinition(Class beanClass) {
       this(beanClass, null);
    }

    public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
       this.beanClass = beanClass;
       this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
    }
	//设置作用域,scope的set方法比较特殊,不是直接赋值,所以这里没有省略
    public void setScope(String scope) {
       this.scope = scope;
       this.singleton = SCOPE_SINGLETON.equals(scope);
       this.prototype = SCOPE_PROTOTYPE.equals(scope);
    }
	//判断是否为singleton
    public boolean isSingleton() {
       return this.singleton;
    }
    //判断是否为prototype
    public boolean isPrototype() {
       return this.prototype;
    }
	
    //其他get、set方法省略
}

给XML的bean标签增加一个scope属性

<!--scope.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="s_prototype" class="org.springframework.test.bean.Student" scope="prototype">
        <property name="name" value="小红同学"></property>
    </bean>
    <!--增加一个单例的Bean作为对比-->
    <bean id="s_singleton" class="org.springframework.test.bean.Student" scope="singleton">
        <property name="name" value="小明同学"></property>
    </bean>
</beans>

将来XmlBeanDefinitionReader解析XML成BeanDefinition,就可以获取scope属性的值,然后设置BeanDefinition

代码大致如下,整合到doLoadBeanDefinitions很简单,这里就省略了

String beanScope = bean.attributeValue("scope");
if (StrUtil.isNotEmpty(beanScope)) {
	beanDefinition.setScope(beanScope);
}

修改一下实例化Bean的代码

public abstract class AbstractAutowireCapableBeanFactory 
    extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    
    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
		Object bean = null;
		try {
			bean = createBeanInstance(beanDefinition);
			applyPropertyValues(beanName, bean, beanDefinition);
			initializeBean(beanName, bean, beanDefinition);
		} catch (Exception e) {
			throw new BeansException("Instantiation of bean failed", e);
		}
		registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        //只有Scope为singleton的Bean才保存起来
		if (beanDefinition.isSingleton()) {
			addSingleton(beanName, bean);
		}
		return bean;
	}
    
    protected void registerDisposableBeanIfNecessary(
        String beanName, Object bean, BeanDefinition beanDefinition) {
        //只有单例Bean才将其注册成销毁Bean
        if (beanDefinition.isSingleton()) {
			if (bean instanceof DisposableBean 
                || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
            	DisposableBeanAdapter a = 
                new DisposableBeanAdapter(bean,beanName,beanDefinition);
				registerDisposableBean(beanName, a);
			} 
        }
	}
}

再修改一下DefaultListableBeanFactory中提前实例化所有单例的方法preInstantiateSingletons

@Override
public void preInstantiateSingletons() throws BeansException {
    beanDefinitionMap.forEach((beanName, beanDefinition) -> {
        //只有作用域是单例的Bean,才提前初始化
        if (beanDefinition.isSingleton()) {
            getBean(beanName);
        }
    });
}

由于beanName不能重复,所以不用修改AbstractBeanFactory#getBean,当试图从容器中获取非单例Bean时,一定会走createBean逻辑,因为非单例Bean不可能存放在单例Bean注册表中

所以每次获取非单例Bean,都会走一遍出了销毁外的生命周期流程,并且每次都会得到新的Bean实例

测试一下

ClassPathXmlApplicationContext context =
        new ClassPathXmlApplicationContext("classpath:scope.xml");
//先测试单例Bean
Student sSingleton1 = context.getBean("s_singleton", Student.class);
Student sSingleton2 = context.getBean("s_singleton", Student.class);
//sSingleton1和sSingleton2是同一个对象
assert sSingleton1 == sSingleton2;

//再测试prototype
Student sPrototype1 = context.getBean("s_prototype", Student.class);
Student sPrototype2 = context.getBean("s_prototype", Student.class);
assert  sPrototype1 != sPrototype2;

//关闭容器
context.close();

由于Student仍然实现了InitializingBean和DisposableBean,所以初始化和销毁方法会被执行

初始化方法执行了三次,其中一次来自refresh容器时单例Bean的初始化,两次来自对Prototype的getBean

销毁方法执行了一次,来自容器关闭时单例Bean的销毁

至此,Bean的生命周期如下

graph TB;
    A(从源加载BeanDefinition并注册进容器);
    A --> B(应用BeanFactoryPostProcessor修改BeanDefinition);
    B --> C(开始实例化Bean-构造Bean);
    C --> D(属性填充)
    D --> X(BeanFactoryAware)
    X --> E(前初始化#ApplicationContextAware)
    E --> F(初始化->InitializingBean->init-method)
    F --> G(后初始化)
    G --> H(得到成品Bean并使用)
    H --> Z{Scope?}
    Z --prototype--> J((结束))
    Z --singleton--> I(销毁->DisposableBean->destroy-method)
    I --> J((结束))

17 FactoryBean

FactoryBean也是一种特殊的Bean,翻译是工厂Bean,也就是创建其他Bean的工厂

从容器获取这种Bean时,会调用FactoryBean的getObject方法,并将该方法的返回值作为成品Bean返回

现在FactoryBean很少用到了,因为@Bean注解修饰的方法,可以完美替代FactoryBean,不过为了完整,这里还是介绍一下

public interface FactoryBean<T> {
    T getObject() throws Exception;
    //是否是单例
    boolean isSingleton();
}

FactoryBean实例化流程跟其他普通Bean一样

当实例化流程走完后需要判断一下,如果是FactoryBean类型的,则需要调用其getObject得到最终的成品Bean,然后根据是否singleton判断是否应该把成品Bean缓存起来

所以AbstractBeanFactory中再增加一个Map集合用于保存单例类型的FactoryBean

AbstractBeanFactory增加如下代码

public abstract class AbstractBeanFactory 
    extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
    //保存所有单例FactoryBean
	private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    //getBean流程改成:得到Bean后并不立即返回,而是先调用getObjectForBeanInstance判断是否为FactoryBean
    @Override
	public Object getBean(String beanName) throws BeansException {
        //先从单例bean注册表中获取
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null) {
            return getObjectForBeanInstance(sharedInstance, beanName);
        }

        //没有找到,则直接创建Bean返回
        BeanDefinition beanDefinition = getBeanDefinition(beanName);
        Object bean = createBean(beanName, beanDefinition);
        return getObjectForBeanInstance(bean, beanName);
    }
    
    protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        Object object = beanInstance;
        //先判断是否是FactoryBean类型的Bean,不是的话直接返回,跟之前流程没什么区别
        if (object instanceof FactoryBean factoryBean) {
            try {
                //是单例,则从factoryBeanObjectCache获取
                if (factoryBean.isSingleton()) {
                    object = factoryBeanObjectCache.get(beanName);
                    if (object == null) {
                        object = factoryBean.getObject();
                        factoryBeanObjectCache.put(beanName, object);
                    }
                }
                //不是单例,则直接调用getObject创建
                else {
                    object = factoryBean.getObject();
                }
            } catch (Exception ex) {
                throw new BeansException("FactoryBean抛出异常", ex);
            }
        }
        return object;
    }
}

测试,准备一个FactoryBean

public class PersonFactoryBean implements FactoryBean<Person> {
    @Override
    public Person getObject() throws Exception {
        //模拟创建复杂Bean
        IDCard card = new IDCard("114514");
        Person person = new Person(card, "李四");
        return person;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

再准备一个XML文件

<!-- factory-bean.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="person" class="org.springframework.test.bean.PersonFactoryBean">
    </bean>
</beans>

测试代码如下

ClassPathXmlApplicationContext context = 
    new ClassPathXmlApplicationContext("classpath:factory-bean.xml");
//factory-bean.xml里明明定义的是PersonFactoryBean类型的Bean,但是返回的却是Person类型的Bean
Person person = context.getBean("person", Person.class);
assert person != null;
person.sayHello();

作为产生其他Bean的工厂,FactoryBean本身至少应该是单例的

18 事件机制

ApplicationContext提供了完善的事件监听和发布功能,是典型的观察者模式

涉及的组件如下

ApplicationEvent表示事件对象

public abstract class ApplicationEvent extends EventObject {
    public ApplicationEvent(Object source) {
       super(source);
    }
}

ApplicationListener表示一个事件监听器

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    //event就是事件对象,表示该监听器对哪种事件感兴趣
    void onApplicationEvent(E event);
}

ApplicationEventPublisher表示事件发布器

public interface ApplicationEventPublisher {
	//event表示发布哪种事件
    void publishEvent(ApplicationEvent event);
}

ApplicationEventMulticaster表示多播器,用来注册、移除事件监听器,以及广播事件

public interface ApplicationEventMulticaster {
    //注册监听器
    void addApplicationListener(ApplicationListener<?> listener);
    //移除监听器
    void removeApplicationListener(ApplicationListener<?> listener);
	//广播事件
    void multicastEvent(ApplicationEvent event);
}

原理也很简单,在ApplicationContext的refresh方法中,获取到所有ApplicationListener类型的Bean,然后作为事件监听器注册到多播器里

将来发布事件时,ApplicationEventPublisher会调用多播器的multicastEvent方法,并将事件对象作为参数

由于多播器已经持有了所有的事件监听器,所有multicastEvent遍历所有的监听器,根据监听器的泛型判断遍历到的监听器是否对当前事件感兴趣,如果感兴趣就调用监听器的onApplicationEvent方法,并将事件对象作为参数

代码实现也很简单

由于多播器的注册和移除事件监听器的方法是同样的,所有交给一个抽象的实现类来实现这两个方法

AbstractApplicationEventMulticaster

public abstract class AbstractApplicationEventMulticaster 
    implements ApplicationEventMulticaster, BeanFactoryAware {
	
    //用于保存所有的事件监听器
    public final Set<ApplicationListener<ApplicationEvent>> listeners = new HashSet<>();

    private BeanFactory beanFactory;
	//给多播器注册监听事件
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
       applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }
	//移除监听事件
    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
       applicationListeners.remove(listener);
    }
	//多播器需要获取所有监听器Bean,故而需要跟BeanFactory打交道
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
       this.beanFactory = beanFactory;
    }
}

SimpleApplicationEventMulticaster实现类用于广播事件

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
       setBeanFactory(beanFactory);
    }

    @Override
    public void multicastEvent(ApplicationEvent event) {
       //遍历所有事件监听器
       for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
           //判断当前遍历到的事件监听器是否对event事件感兴趣
           if (supportsEvent(applicationListener, event)) {
             //执行事件监听器方法
             applicationListener.onApplicationEvent(event);
          }
       }
    }

    //监听器是否对该事件感兴趣
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> 
                                    applicationListener, ApplicationEvent event) {
       Type type = applicationListener.getClass().getGenericInterfaces()[0];
       Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
       String className = actualTypeArgument.getTypeName();
       Class<?> eventClassName;
       try {
          eventClassName = Class.forName(className);
       } catch (ClassNotFoundException e) {
          throw new BeansException("wrong event class name: " + className);
       }
       return eventClassName.isAssignableFrom(event.getClass());
    }
}

可以通过ApplicationContext发布事件,所有ApplicationContext也是一个事件发布器

public interface ApplicationContext extends 
    ListableBeanFactory, HierarchicalBeanFactory, ResourceLoader, ApplicationEventPublisher {

}

在其实现类AbstractApplicationContext中初始化多播器、注册事件监听器,增加代码如下

public abstract class AbstractApplicationContext 
    extends DefaultResourceLoader implements ConfigurableApplicationContext {
    //多播器也会注册成Bean,将多播器Bean的名称变成常量
    public static final String 
        APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
	//多播器对象
	private ApplicationEventMulticaster applicationEventMulticaster;
    
    @Override
	public void refresh() throws BeansException {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		invokeBeanFactoryPostProcessors(beanFactory);
		registerBeanPostProcessors(beanFactory);

		//初始化多播器
		initApplicationEventMulticaster();
		//注册事件监听器
		registerListeners();

		beanFactory.preInstantiateSingletons();

		//发布容器刷新完成的事件
		finishRefresh();
	}
    
    //初始化多播器
    protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.addSingleton(
            APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster
        );
	}
    
    //注册事件监听器
    protected void registerListeners() {
        //得到所有ApplicationListener类型的Bean
		Collection<ApplicationListener> c = getBeansOfType(ApplicationListener.class).values();
		//注册到多播器
        for (ApplicationListener applicationListener : c) {
			applicationEventMulticaster.addApplicationListener(applicationListener);
		}
	}
    
    //发布事件的方法
    @Override
	public void publishEvent(ApplicationEvent event) {
        //事件发布器本质还是通过多播器来发布事件
		applicationEventMulticaster.multicastEvent(event);
	}
    
    //发布一个容器刷新完成的事件
    protected void finishRefresh() {
        //ContextRefreshedEvent没什么好说的,自行增加该类
		publishEvent(new ContextRefreshedEvent(this));
	}
    
}

Spring中使用注解@EventListener修饰方法来声明一个事件监听器,其本质还是创建一个ApplicationListener实现类,然后在其onApplicationEvent方法里调用被注解修饰的方法,最后将ApplicationListener实现类注册进多播器

Spring有一个特殊的Bean:SmartInitializingSingleton,只有容器中所有单例bean都初始化之后,才会初始化SmartInitializingSingleton类型的bean

//Spring中注解形式的事件监听器,会被解析成ApplicationListener实现类,原理大致如下
@Configuration
public class Config {
    //AnnotationConfigApplicationContext也是一个上下文容器实现类,使用配置类作为BeanDefinition源
    @Bean
    public SmartInitializingSingleton parseAnno(AnnotationConfigApplicationContext context) {
        //SmartInitializingSingleton是一个函数时接口,
        //初始化该类bean时就会回调afterSingletonsInstantiated()
        SmartInitializingSingleton smartInitializingSingleton = () -> {
            //遍历所有bean的所有方法
            for (String name : context.getBeanDefinitionNames()) {
                Object bean = context.getBean(name);
                for (Method method : bean.getClass().getDeclaredMethods()) {
                    //如果标注了@EventListener,并且方法至少有一个参数
                    if (method.isAnnotationPresent(EventListener.class) 
                        && method.getParameterTypes().length > 0) {

                        ApplicationListener listener = realEvent -> {
                            Class<?> targetType = method.getParameterTypes()[0];
                            //只有当前监听器感兴趣的事件targetType才与真实发生的事件匹配
                            if (targetType.isAssignableFrom(realEvent.getClass())) {
                                try {
                                    //间接调用该方法
                                    method.invoke(bean, realEvent);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        };
                        //向容器添加监听器
                        context.addApplicationListener(listener);
                    }
                }
            }
        };
        return smartInitializingSingleton;
    }
}