AOP:juejin.cn/spost/73683…
高级部分:juejin.cn/post/736905…
简简单单写个IOC
菜鸟一枚,如果文档有错误的地方,请指正
阅读过Spring源码的人都知道,Spring封装之深,抽象程度之高令人咂舌,其分支太多,经常迷失在分支里忘记了主干在哪,或者说压根不知道主干在哪,不知道从哪开始读,没有一个阅读主线
文档从零开始实现一个最简单的IOC容器(Map集合),然后再此基础上一点点迭代实现Spring的功能,每次迭代所增加的类或代码都只实现了其本职最基础最简单的功能
在一切开始前,准备几个类
人员类,省略了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时才会实例化,上面几个接口或类的关系如下
至此,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
继承自
AutowireCapableBeanFactory、ListableBeanFactory和ConfigurableBeanFactory,同时拥有它们的能力
有些接口的出现只是为了符合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;
}
}
完整的继承关系图如下
注重实践哦~~~
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,流程大致如下
- 回调BeanFactoryPostProcessor,对现有的BeanDefinition进行修改
- 遍历所有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的初始化和销毁方法有下面四种定义方法
- XML中指定init-method和destroy-method
- Bean继承InitializingBean和DisposableBean接口
- 方法上加注解PostConstruct和PreDestroy
- 配置类中使用@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;
}
}