概述
前言
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 {
...
}
-
Environment接口,该接口代表了当前运行的容器的环境信息,接口规定了2种逻辑模型(profiles和properties),它的父接口PropertyResolver 提供了获取环境变量值的方法。
public interface Environment extends PropertyResolver { String[] getActiveProfiles(); ... }
-
ListableBeanFactory和HierarchicalBeanFactory接口,这2个接口上面已经讲过了,通过继承这2个接口,ApplicationContext 接口获得了IOC容器最基本的功能。
-
MessageSource接口,通过继承这个接口,容器获得了处理国际化信息的能力。
public interface MessageSource { String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale); ... }
-
ApplicationEventPublisher接口,这个接口使得容器具备事件发布的功能,这个功能很有用,容器创建过程中会发布很多事件,可以监听这些事件然后执行相关的逻辑。
@FunctionalInterface public interface ApplicationEventPublisher { void publishEvent(Object event); }
-
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。由下图可以明显看出分成了两个体系。
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容器概念及类关系详解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复