发布于
SpringIOC整体设计
从接口开始
先来看看4个接口BeanFactory、SingletonBeanRegistry、AliasRegistry、BeanDefinitionRegistry
AliasRegistry定义了别名的接口而BeanDefinitionRegistry继承了AliasRegistry意味着BeanDefinitionRegistry也拥有别名的能力,另外他还扩展了注册BeanDefinition的能力。而SingletonBeanRegistry是一个单例的注册器被注册的是类的实例而不是定义。SingletonBeanRegistry、AliasRegistry、BeanDefinitionRegistry三个接口定义了3种注册器的能力。在本文中我们把这些接口统称为注册器。
再来看看BeanFactory他实际上主要定义了了对Bean的获取的能力根据名称获取或者是根据类型匹配获取。它的子接口定义了很多对工厂内部Bean查看管理的能力。这里要注意ConfigurableBeanFactory因为它继承了SingletonBeanRegistry,在这个接口之前实际上BeanFactory没有定义任何向工厂注册Bean的能力。
我们梳理一下Factory定义了对获取Bean及其配置信息的能力,而Registry定义了注册Bean的能力。
工厂初始化
XmlBeanFactory实际上已经被废弃但是我们可以从它入手学习会更简单,我们先来看一下XmlBeanFactory的源码。其实非常简单重点在与DefaultListableBeanFactory和XmlBeanDefinitionReader上面,本文主要讲解IOC的实现原理对于怎么解析Bean的XML文件不会过多讲解,毕竟这个时代没有人会直接使用spring-beans包,和传统的XML文件定义类。
//DefaultListableBeanFactory实现了之前提到的接口,它提供了一个完整的IOC实现
public class XmlBeanFactory extends DefaultListableBeanFactory {
//XmlBeanDefinitionReader实现了XML的解析并且注册到Factory
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//加载xml文件,解析并且注册到工厂
this.reader.loadBeanDefinitions(resource);
}
}
我们从this.reader.loadBeanDefinitions(resource);这行代码往下跟踪找到了第一个需要关注的地方
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//处理IMPORT
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//处理别名
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//处理bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//处理beans 递归调用之前的
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
importBeanDefinitionResource和doRegisterBeanDefinitions还是XML解析的实现与IOC本身无关我们忽略它。首先我们来看看别名的注册
protected void processAliasRegistration(Element ele) {
//获取元素
String name = ele.getAttribute(NAME_ATTRIBUTE);
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
//校验
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
//有效导入无效忽略
if (valid) {
try {
//注册别名 重点在这里 getReaderContext().getRegistry()获取的就是XmlBeanFactory本身
getReaderContext().getRegistry().registerAlias(name, alias);
}
catch (Exception ex) {
getReaderContext().error("Failed to register alias '" + alias +
"' for bean with name '" + name + "'", ele, ex);
}
//别名事件触发
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}
registerAlias方法实现了别名的注册回想一下之前说过的AliasRegistry接口这个方法就是在这里定义的。具体的功能都是在SimpleAliasRegistry类中实现的。XmlBeanFactory继承了这个类。本质就是一个aliasMap的ConcurrentHashMap实现的大家可以自己去看一下源码这里就不展开说了。
再来看一下processBeanDefinition
//registry就是XmlBeanFactory本身
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析bean定义
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//自定义装饰器扩展
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册到工厂 同时也会组册别名
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
class BeanDefinitionReaderUtils{
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 组册类定义
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 注册别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
}
我们可以看到这里的registerBeanDefinition方法就是在BeanDefinitionRegistry接口中定义的,BeanDefinitionRegistry还继承了AliasRegistry所以它当然可以注册别名。registerBeanDefinition的实现在DefaultListableBeanFactory类中,主要就是对一个名为beanDefinitionMap的对象操作,大家可以自行去阅读源码这里就不贴代码了。
注:fireAliasRegistered和fireComponentRegistered不会再本文中提及后续会单独写一篇文章去介绍它,本文为了让读者更专注IOC的核心功能实现。
到目前为止,我们可以知道XmlBeanDefinitionReader的本质就是调用注册器把解析到的信息注册到容器中。
获取一个Bean
当我们执行一行获取Bean的代码时
Map<String, BeanA> beansOfType = xmlBeanFactory.getBeansOfType(BeanA.class);
BeanA beanA = (BeanA)xmlBeanFactory.getBean("beanA");
最终都掉用了AbstractBeanFactory类的doGetBean方法,这个方法的实现比较复杂,大家需要有点耐心看下去。为了阅读方便这里删除了log的代码
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//可能是别名翻译一下 名字包含&前缀去除掉
String beanName = transformedBeanName(name);
Object bean;
//可能有直接注册实例对象的或者已经被创建的单例
//这里要提及几个核心的Map
//singletonObjects Map中的Bean已经完全初始化好了,可以直接使用
//earlySingletonObjects Map中的Bean处在创建中
//singletonFactories Map中存放Bean对应的工厂
//这里会先从singletonObjects中获取 如果没有根据singletonsCurrentlyInCreation判断是否在创建中,不是直接返回null
//如果是创建中从earlySingletonObjects中获取
//如果也没有获取到获取singletonObjects的对象锁然后从singletonFactories中获取工厂并且创建
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//检查是不是有循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 检查一下 如果工厂没有定义这个bean就看一下父工厂
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
//校验
if (!typeCheckOnly) {
/* 如果创建bean不是为了类型检查,则要标记当前bean已经被创建或者即将被创建以便于BeanFactory可以优化重复创建的bean的缓存 */
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
//大家应该记得之前注册的BeanDefinition吧,getMergedLocalBeanDefinition内部获取BeanDefinition后
//会去查看是否有Parent BeanDefinition有的话继承它的属性 没有的话把自己包装成一个RootBeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 处理依赖 如果有配置DependsOn这里会先初始化依赖类
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
//利用dependentBeanMap可以判断出是否循环依赖
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
//递归调用 先创建依赖类
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 如果是单例Bean
if (mbd.isSingleton()) {
//看下面单独介绍 创建一个单例对象并且返回
sharedInstance = getSingleton(beanName, () -> {
try {
//利用注册的信息创建Bean
//createBean中实现了lookup-method和replace-method
//和BeanPostProcessor
//以及创建实例
//填充属性 AutoWrite也是这里实现的
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
//同上
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//自定义scope扩展
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
// Check if required type matches the type of the actual bean instance.
// 检查类型是否符合
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
总结
SpringIOC大体上抽象成了两个部分一个注册器,一个是工厂,工厂通过注册器提供的信息创建Bean。
IOC的实现其实十分复杂,这里只是做了简单的概念性介绍,后续会单独去讲解BeanPostProcessor接口提供的扩展能力、各种事件通知、Aware接口、Bean初始化流程等等。