Spring 源码继续开整!java
在 XML 文件解析流程一文中,松哥和你们分享了 Spring 中配置文件的加载方式,若是小伙伴们还没看过,必定先看一下,这有助于更好的理解本文,传送门:Spring 源码第一篇开整!配置文件是怎么加载的?。bootstrap
还记得该篇文章中的代码吗?缓存
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory.getBean(User.class);
System.out.println("user = " + user);
复制代码
当 ClassPathResource 将文件以 IO 流的方式输出后,接下来就是构造 XmlBeanFactory ,XmlBeanFactory 功能有限,它的大部分功能都在它的父类 DefaultListableBeanFactory 中实现了,而 DefaultListableBeanFactory 也至关因而容器的始祖,为何这么说呢?咱们今天就来讲一说这个话题。并发
本文是 Spring 源码解读第七篇,阅读本系列前面文章有助于更好的理解本文:app
要说 XmlBeanFactory 就不得不先说它的父类 DefaultListableBeanFactory,由于 XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了,XmlBeanFactory 只是对 IO 流的读取作了一些定制而已。ide
DefaultListableBeanFactory 是一个完整的、功能成熟的 IoC 容器,若是你的需求很简单,甚至能够直接使用 DefaultListableBeanFactory,若是你的需求比较复杂,那么经过扩展 DefaultListableBeanFactory 的功能也能够达到,能够说 DefaultListableBeanFactory 是整个 Spring IoC 容器的始祖。源码分析
咱们先来看一下 DefaultListableBeanFactory 的继承关系:post
从这张类的关系图中能够看出,DefaultListableBeanFactory 实际上也是一个集大成者。在 Spring 中,针对 Bean 的不一样操做都有不一样的接口进行规范,每一个接口都有本身对应的实现,最终在 DefaultListableBeanFactory 中将全部的实现汇聚到一块儿。从这张类的继承关系图中咱们大概就能感觉到 Spring 中关于类的设计是多么厉害,代码耦合度很是低。ui
这些类,在本系列后面的介绍中,大部分都会涉及到,如今我先大概介绍一下每一个类的做用,你们先混个脸熟:this
上面的内容可能看的你们眼花缭乱,松哥这里经过几个简单实际的例子,来带你们使用一下 DefaultListableBeanFactory 的功能,可能你们的理解就比较清晰了。
DefaultListableBeanFactory 做为一个集大成者,提供了很是多的功能,咱们一个一个来看。
首先文章中一开始的三行代码咱们能够对其略加改造,由于咱们已经说了 XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了,XmlBeanFactory 只是对 IO 流的读取作了一些定制而已,文件的读取主要是经过 XmlBeanDefinitionReader 来完成的(本系列前面文章已经讲过),咱们能够对文章一开始的三行代码进行改造,以便更好的体现“XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了”:
ClassPathResource res=new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
User user = factory.getBean(User.class);
System.out.println("user = " + user);
复制代码
使用前四行代码代替 XmlBeanFactory,这样 XmlBeanFactory 的功能是否是就很明确了?就是前四行代码的功能。
动态注册 Bean,这是 DefaultListableBeanFactory 的功能之一,不过准确来讲应该是动态注册 BeanDefinition 。
咱们先来看一个简单的例子:
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
userBeanDefinition.setPropertyValues(pvs);
userBeanDefinition.setBeanClass(User.class);
defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition);
User user = defaultListableBeanFactory.getBean(User.class);
System.out.println("user = " + user);
复制代码
首先咱们本身手动构建一个 DefaultListableBeanFactory 对象。固然也可使用前面的 XmlBeanFactory。
而后再手动构建一个 GenericBeanDefinition。在前面的文章中,松哥和你们讲过,如今默认使用的 BeanDefinition 就是 GenericBeanDefinition,因此这里咱们本身也手动构建一个 GenericBeanDefinition。有了 GenericBeanDefinition 以后,咱们设置相关的类和属性。
接下来再将 userBeanDefinition 注册到 defaultListableBeanFactory。注册完成以后,咱们就能够从 defaultListableBeanFactory 中获取相应的 Bean 了。
这里说一句题外话,但愿你们在阅读本系列每一篇文章的时候,可以将本系列先后文章联系起来一块儿理解,这样会有不少意料以外的收获。例如上面的,咱们既能够声明一个 DefaultListableBeanFactory,也能够声明一个 XmlBeanFactory,那你大概就能据此推断出 XmlBeanFactory 的主要目的可能就是对资源文件进行读取和注册。
那么究竟是怎么注册的呢?咱们来看一下 defaultListableBeanFactory.registerBeanDefinition 方法的定义:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
复制代码
registerBeanDefinition 方法是在 BeanDefinitionRegistry 接口中声明的,DefaultListableBeanFactory 类实现了 BeanDefinitionRegistry 接口,并实现了该方法,咱们来看分析下该方法:
这即是 registerBeanDefinition 方法的工做流程。
有小伙伴会说,这个方法从头至尾都是 BeanDefinition,跟 Bean 有什么关系呢?
咋一看确实好像和 Bean 没有直接关系。
其实这涉及到另一个问题,就是 Bean 的懒加载。这个时候先把 BeanDefinition 定义好,等到真正调用 Bean 的时候,才会去初始化 Bean。咱们能够在 User 类的构造方法中打印日志看下,以下:
public class User {
private String username;
private String address;
public User() {
System.out.println("--------user init--------");
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
复制代码
从下图能够看到,当 BeanDefinition 注册完成后,User 并无初始化,等到 getBean 方法被调用的时候,User 才初始化了。
须要注意的是,咱们平常开发中使用的 ApplicationContext 并不是懒加载,这个在松哥的 Spring 入门视频中能够看到效果【www.bilibili.com/video/BV1Wv…】,具体原理松哥将在本系列后面的文章中和你们分享。
那么若是不想懒加载该怎么办呢?固然有办法。
在 DefaultListableBeanFactory 中还有一个 preInstantiateSingletons 方法能够提早注册 Bean,该方法是在 ConfigurableListableBeanFactory 接口中声明的,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口并实现了接口中的方法:
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
复制代码
preInstantiateSingletons 方法的总体逻辑比较简单,就是遍历 beanNames,对符合条件的 Bean 进行实例化,并且你们注意,这里所谓的提早初始化其实就是在咱们调用 getBean 方法以前,它本身先调用了一下 getBean。
咱们能够在案例中手动调用该方法:
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
userBeanDefinition.setPropertyValues(pvs);
userBeanDefinition.setBeanClass(User.class);
defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition);
defaultListableBeanFactory.preInstantiateSingletons();
User user = defaultListableBeanFactory.getBean(User.class);
System.out.println("user = " + user);
复制代码
此时在调用 getBean 方法以前,User 就已经初始化了,以下图:
DefaultListableBeanFactory 中另一个重量级方法就是 getBean 了。不过 getBean 方法的真正实现是在 DefaultListableBeanFactory 的父类 AbstractBeanFactory 中,具体的实现方法是 doGetBean,原本想和你们子在这里聊一聊这个问题,可是发现这是一个很是庞大的问题,BeanFactory 和 FactoryBean 都还没和你们分享,因此这个话题咱们仍是暂且押后,一个点一个点来。
好啦,今天就先说这么多,每篇源码我都尽可能配置套一些小案例来演示,这样避免你们看的太枯燥了,咱们下周继续~
若是你们以为有收获,记得点个在看鼓励下松哥哦~