我是靠谱客的博主 优雅蚂蚁,最近开发中收集的这篇文章主要介绍Spring源码深度解析(一):IOC容器概念及类关系详解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

Spring容器的两大特性:IOC和AOP。

本文先来说IOC,如果对于IOC概念还不太理解的同学请先看这篇文章 Spring IOC概念详解及入门案例。

首先我们统一一下概念,网上资料中常说的"IOC容器",“Bean容器”,“Bean工厂"等都是指同样的概念,本文统一使用"IOC容器”。

本系列文章将从源码级别来分析Spring,力求通俗易懂、深入透彻。

正文

一、Bean工厂

1、BeanFactory接口

IOC容器说简单点,其实就是一个Bean工厂,它提供了一个工厂方法,入参是Bean的名称,返参就是对应的Object对象,容器的顶层接口如下:

public interface BeanFactory {
	// 工厂方法,根据Bean名称获取Bean对象,接口中还有getBean的重载方法
	Object getBean(String name) throws BeansException;
	// 是否包含某个Bean
	boolean containsBean(String name);
	// 是否单例
	boolean isSingleton(String name)
	// 获取Bean的类型
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	...
}

再来看2个BeanFactory接口的子接口:HierarchicalBeanFactory和ListableBeanFactory。

public interface HierarchicalBeanFactory extends BeanFactory {
	// 这个接口可以使Bean工厂实现父子容器的功能
	BeanFactory getParentBeanFactory();
	...
}
// 对BeanFactory接口的扩展,可以批量获取容器中所有的Bean实例
public interface ListableBeanFactory extends BeanFactory {

	int getBeanDefinitionCount();

	String[] getBeanDefinitionNames();

	String[] getBeanNamesForType(@Nullable Class<?> type);
	...
}

2、AutowireCapableBeanFactory接口

BeanFactory接口的子接口,增加了一个重要的功能:即自动装配。作用就是当一个类A依赖了另一个类B(A类持有B类型的属性),在创建A的过程中,Spring会从容器中拿到一个B类型的实例,然后注入到A类的属性中。接口中提供了一系列装配Bean的方法。

public interface AutowireCapableBeanFactory extends BeanFactory {

	<T> T createBean(Class<T> beanClass) throws BeansException;

	void autowireBean(Object existingBean) throws BeansException;

	Object configureBean(Object existingBean, String beanName) throws BeansException;

	Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;

	Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;

	void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
			throws BeansException;

	void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
	...
}

3、ConfigurableBeanFactory接口

该接口继承了HierarchicalBeanFactory,使得容器具备可配置的功能,其实就是提供了一堆get set方法,能够使容器具备更多的功能。其中比较重要的有一个方法:添加Bean后置处理器。

void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

4、ConfigurableListableBeanFactory接口

继承了上述所有的接口,也是BeanFactory接口体系的最后一个接口,拥有以上接口的所有功能,除此之外,它还提供了分析和修改 bean 定义以及预实例化单例的方法。

小结:上面这6个接口就规定了IOC容器的基本功能和行为,接下来还有几个相关的接口,规定了IOC容器是怎么注册Bean的,我们继续看。

5、SingletonBeanRegistry接口

上面的BeanFactory接口定义了获取Bean实例的工厂方法,那么Bean实例从哪里来呢?那么SingletonBeanRegistry接口就定义了Bean注册的方法,为什么接口名字会有一个Singleton呢,是因为单例Bean只创建一次,然后保存下来(存在Map中),下次用的时候直接去取,而多实例Bean每次都要创建,不用保存。所以该接口是专门针对单例Bean注册的接口。

public interface SingletonBeanRegistry {
	// 注册单例Bean
	void registerSingleton(String beanName, Object singletonObject);
	// 获取单例Bean
	Object getSingleton(String beanName);

	boolean containsSingleton(String beanName);

	String[] getSingletonNames();

	int getSingletonCount();

	Object getSingletonMutex();
}

6、BeanDefinition接口

上面2个接口规定了容器获取Bean和注册Bean的行为,属于高度抽象的概念。实际我们使用容器的时候是通过扫描包路径,获取被@Component等注解注释的类,然后注册到容器中的。那么在扫描过程中,我们需要拿到Bean的字节码信息,通过反射来查看类上面有没有@Component信息,然后判断要不要进行注册。那么这些字节码信息就由BeanDefinition接口承载。

我们看到接口中的方法都是在描述类的信息,比如是不是单例、是不是懒加载等等,所以这个接口叫做BeanDefinition(bean定义)。这个接口有一些子接口和实现类,分别代表不同途径扫描得到的Bean的信息。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
	void setBeanClassName(@Nullable String beanClassName);
	String getBeanClassName();
	
	void setScope(@Nullable String scope);
	String getScope();

	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();

	void setDependsOn(@Nullable String... dependsOn);
	String[] getDependsOn();

	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();

	void setPrimary(boolean primary);
	boolean isPrimary();

	void setFactoryBeanName(@Nullable String factoryBeanName);
	String getFactoryBeanName();

	void setFactoryMethodName(@Nullable String factoryMethodName);
	String getFactoryMethodName();

	ConstructorArgumentValues getConstructorArgumentValues();
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	MutablePropertyValues getPropertyValues();
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	void setInitMethodName(@Nullable String initMethodName);
	String getInitMethodName();

	void setDestroyMethodName(@Nullable String destroyMethodName);
	String getDestroyMethodName();

	void setRole(int role);
	int getRole();

	void setDescription(@Nullable String description);
	String getDescription();

	ResolvableType getResolvableType();

	boolean isSingleton();

	boolean isPrototype();

	boolean isAbstract();

	String getResourceDescription();

	BeanDefinition getOriginatingBeanDefinition();
}

7、BeanDefinitionRegistry接口

上面的BeanDefinition接口只是承载Bean信息,想要使用这些信息,还需要注册动作,BeanDefinitionRegistry接口就是干这个事的。

public interface BeanDefinitionRegistry extends AliasRegistry {
	// 注册BeanDefinition 
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	// 获取BeanDefinition 
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	boolean containsBeanDefinition(String beanName);

	String[] getBeanDefinitionNames();

	int getBeanDefinitionCount();

	boolean isBeanNameInUse(String beanName);
}

8、DefaultSingletonBeanRegistry类

这个类实现了上面第2个接口 SingletonBeanRegistry,实例了单例Bean的注册过程,我们看到类有一个Map类型的属性singletonFactories,这个Map其实保存的就是单例Bean,注册Bean的方法就是往这个Map中放入对象,获取Bean的方法就是从Map中获取Value。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	// 属性保存的是beanName和bean实例的对应关系
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	...
	
	// 注册bean的过程即往Map中添加k-v对
	@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		...
		addSingleton(beanName, singletonObject);
	}
	
	// 最终调用Map.put()方法
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			...
		}
	}

9、FactoryBeanRegistrySupport类

这个类继承了DefaultSingletonBeanRegistry类,扩展了一种Bean注册的方式(对实现了FactoryBean接口的类进行注册)。

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

	/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		...
	}

	// 最终调到了FactoryBean接口的getObject()方法
	private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {
		...
		object = factory.getObject();
		...
	}

10、AbstractBeanFactory类

该类一方面继承了FactoryBeanRegistrySupport,拥有了注册Bean的行为。另一方面实现了ConfigurableBeanFactory接口,将“容器可配置”这个理念得到实现,我们看到AbstractBeanFactory类有很多属性并实现了相关的get set方法。

另一个比较重要的点是,一个接口继承体系中的第一个实现类一般是抽象类,它实现了一些公共的方法,并提供了一些模板方法,供子类来实现。该类提供了3个模板方法:

protected abstract boolean containsBeanDefinition(String beanName);

protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException;

我们来看该类里面实现了很多方法,最重要的是getBean方法:

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	// 实现getBean方法
	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
	
	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		...
		containsBeanDefinition(); // 调用模板方法
		...
		createBean(1,2,3); // 调用模板方法
		...
}

11、AbstractAutowireCapableBeanFactory类

该类一方面继承了AbstractBeanFactory类,并实现了抽象方法createBean。另一方面实现了AutowireCapableBeanFactory接口,实现了重要的“自动装配”功能。代码不再列举。

12、DefaultListableBeanFactory

这个类是BeanFactory继承体系中的最后一个实现类了,也就是说它具备了IOC容器管理Bean的全部功能。该类一方面继承了AbstractAutowireCapableBeanFactory,实现了containsBeanDefinition和getBeanDefinition两个抽象方法。另一方面,它实现了BeanDefinitionRegistry接口,完成了Bean定义注册的功能,至此,IOC容器关于Bean工厂的类继承体系就结束了。

小结:以上所述的接口和类的集成体系如下图所示,不禁让人感叹,Spring源码的接口设计真是清晰啊,从上往下,接口层层继承,功能逐渐增强;类同样层层继承,分别针对不同的接口进行实现,最终得到一个功能完整的实现类。

二、应用上下文

1、ApplicationContext接口

上面讲的Bean工厂相关的12个接口组成了IOC容器的最基本的功能:即根据Bean名称获取Bean实例。但是我们在使用Spring的时候远远不止这一点功能,我们接着往下看,然后找到了一个接口:ApplicationContext,这个接口继承了BeanFactory及2个子接口,于是它就具备了IOC容器的基本功能。同时,它还继承了一系列其他接口,于是就具备了更加丰富的功能,来看下它都继承了哪些接口。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
	...
}
  1. Environment接口,该接口代表了当前运行的容器的环境信息,接口规定了2种逻辑模型(profiles和properties),它的父接口PropertyResolver 提供了获取环境变量值的方法。

    public interface Environment extends PropertyResolver {
    	String[] getActiveProfiles();
    	...
    }
    
  2. ListableBeanFactory和HierarchicalBeanFactory接口,这2个接口上面已经讲过了,通过继承这2个接口,ApplicationContext 接口获得了IOC容器最基本的功能。

  3. MessageSource接口,通过继承这个接口,容器获得了处理国际化信息的能力。

    public interface MessageSource {
    	String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
    	...
    }
    
  4. ApplicationEventPublisher接口,这个接口使得容器具备事件发布的功能,这个功能很有用,容器创建过程中会发布很多事件,可以监听这些事件然后执行相关的逻辑。

    @FunctionalInterface
    public interface ApplicationEventPublisher {
    	void publishEvent(Object event);
    }
    
  5. ResourcePatternResolver接口,继承该接口可实现加载各类资源的功能。

    public interface ResourcePatternResolver extends ResourceLoader {
    	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
    
    	Resource[] getResources(String locationPattern) throws IOException;
    }
    

综上,ApplicationContext接口首先具备了Bean工厂的基本功能,又继承了很多接口,实现了更多功能,Spring中真正使用的容器均是实现了这个接口的类。由于ApplicationContext扩展了BeanFactory,所以它不再叫Bean工厂了,叫做应用上下文

2、ConfigurableApplicationContext接口

该接口继承了ApplicationContext,并且提供了配置应用上下文的方法。其中有几个比较重要的方法:

void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

void addApplicationListener(ApplicationListener<?> listener);

void refresh() throws BeansException, IllegalStateException;

3、AbstractApplicationContext类

作为应用上下文接口继承体系的最顶层的抽象类,它实现了最基本的公共的方法(主要是实现了ConfigurableApplicationContext接口的方法),并提供3个抽象方法(模板方法)供子类实现。其中该类实现了一个方法refresh(),这个方法非常重要,它定义了应用上下文启动的整体流程。代码不再单列。

4、GenericApplicationContext类

继承了AbstractApplicationContext类,实现了模板方法。这个类有一个重要的属性:beanFactory,这个属性是DefaultListableBeanFactory 类型的(该类属于BeanFactory接口体系)。也就是说,应用上下文是通过聚合而非继承的方式实现Bean工厂的功能。

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	// 属性持有Bean工厂的最终实现类DefaultListableBeanFactory 
    private final DefaultListableBeanFactory beanFactory; 
    // 子类实例化时,会触发该父类构造方法执行,从而实例化属性
	public GenericApplicationContext() { 
        this.beanFactory = new DefaultListableBeanFactory(); // 在构造方法中实例化
    }
}

其中,类中有3个获取Bean工厂的方法,返回的都是同一个属性

public final ConfigurableListableBeanFactory getBeanFactory() {
	return this.beanFactory;
}

然后在应用上下文中操作Bean工厂的行为其实都是在操作属性DefaultListableBeanFactory的同名方法。

public BeanDefinition getBeanDefinition(String beanName) {
    return this.beanFactory.getBeanDefinition(beanName);
}

5、AnnotationConfigApplicationContext类

这个类是应用上下文类体系中的一个实现类,也就是我们常用的注解版的ApplicationContext。它持有一个reader和一个scanner,在构造方法中实例化,并调用父类的refresh()方法启动容器。代码不再列举。

小结:应用上下文类体系的继承关系同样很清晰。每一层都定义了不同的功能。

总结

IOC源码中涉及到的容器类比较多,我们可以将他们分成2类,如下图,一个是BeanFactory,另一个是ApplicationContext。由这两个接口延伸出子类xxxBeanFactory,xxxApplicationContext。由下图可以明显看出分成了两个体系。
图1 DefaultListableBeanFactory
AnnotationConfigApplicationContext

BeanFactory接口代表的是最基础的容器类,定义了容器的最基本行为(方法):getBean()、containsBean()等获取bean、判断bean是否存在的方法。

ApplicationContext也是容器类,它也是继承自BeanFactory接口,不过它还继承了MessageSource(国际化信息)、ApplicationEventPublisher(事件发布机制)等接口,因此它就有了一些别的特性,称为高级容器。

Spring源码中随处可见模板模式,即由一个AbstracXXX类来实现一系列接口,并且实现一些公共方法,但是保留一些扩展接口供子类来实现。我们可以将上图简化一下,得到下图。明显的2个体系已经划分出来了,那么这两个体系有什么关系呢?答案是聚合关系,高级容器GenericApplicationContext中持有普通容器DefaultListableBeanFactory,那么以后跟bean相关的操作都是在DefaultListableBeanFactory中进行的。
在这里插入图片描述
我们使用的容器都是xxxApplicationContext这种高级容器,高级容器持有了DefaultListableBeanFactory这个基本容器,我们知道IOC容器的核心就是反射读取bean的定义信息,然后将其注册到IOC容器中去。于是我们就来看一下DefaultListableBeanFactory这个类,这个类的成员变量有一个Map集合,key是bean的名称,value是BeanDefinition对象,这个对象就是对标记的类的描述信息,为之后反射创建bean实例打基础。再关注一下该类的一个方法:registerBeanDefinition(String beanName,BeanDefinition bd),这个方法很简单,就是往map里面put类定义信息。

/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
	// 前面删除了多余的代码,只重点展示往map中添加k-v对的语句
    this.beanDefinitionMap.put(beanName, beanDefinition);
}

上面说到类定义信息在BeanDefinition接口中定义,被标注@Component注解的类会被扫描到,并且会被反射读取类的一切信息,并封装进BeanDefinition对象。我们来看一下都有哪些信息,如下图,这些方法都是来描述一个bean的,比如:获取bean的类名,获取类的初始化和销毁方法,是否懒加载,获取类的Scope,是否单例模式等等。这些信息在之后创建bean实例的时候会用到。
在这里插入图片描述

从上面的图示,高级容器的接口体系中可以看出,最底层的接口是ConfigurableApplicationContext,这个接口继承了所有父接口中的方法,其中有一个重要的方法是:refresh(),该方法用来刷新IOC容器,当往IOC容器中注册了新的bean定义时,调用此方法去创建bean实例。而最顶层的实现类是AbstractApplicationContext,这个类是一个模板类,实现了大部分的方法,留有一些方法待子类实现,当然也就实现了refresh()方法,这个方法是IOC容器创建的入口,本系列后面的文章我们会详细讲它。
在这里插入图片描述

最后

以上就是优雅蚂蚁为你收集整理的Spring源码深度解析(一):IOC容器概念及类关系详解的全部内容,希望文章能够帮你解决Spring源码深度解析(一):IOC容器概念及类关系详解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部