Spring 源码持续开整!
在 XML 文件解析流程一文中,松哥和大家分享了 Spring 中配置文件的加载形式,如果小伙伴们还没看过,肯定先看一下,这有助于更好的了解本文,传送门:Spring 源码第一篇开整!配置文件是怎么加载的?。
还记得该篇文章中的代码吗?
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 源码解读第七篇,浏览本系列后面文章有助于更好的了解本文:
- Spring 源码解读打算
- Spring 源码第一篇开整!配置文件是怎么加载的?
- Spring 源码第二弹!XML 文件解析流程
- Spring 源码第三弹!EntityResolver 是个什么鬼?
- Spring 源码第四弹!深刻了解 BeanDefinition
- 手把手教你搭建 Spring 源码剖析环境
1.DefaultListableBeanFactory
要说 XmlBeanFactory 就不得不先说它的父类 DefaultListableBeanFactory,因为 XmlBeanFactory 中的大部分性能实际上在 DefaultListableBeanFactory 中就曾经提供好了,XmlBeanFactory 只是对 IO 流的读取做了一些定制而已。
DefaultListableBeanFactory 是一个残缺的、性能成熟的 IoC 容器,如果你的需要很简略,甚至能够间接应用 DefaultListableBeanFactory,如果你的需要比较复杂,那么通过扩大 DefaultListableBeanFactory 的性能也能够达到,能够说 DefaultListableBeanFactory 是整个 Spring IoC 容器的始祖。
咱们先来看一下 DefaultListableBeanFactory 的继承关系:
从这张类的关系图中能够看出,DefaultListableBeanFactory 实际上也是一个集大成者。在 Spring 中,针对 Bean 的不同操作都有不同的接口进行标准,每个接口都有本人对应的实现,最终在 DefaultListableBeanFactory 中将所有的实现汇聚到一起。从这张类的继承关系图中咱们大略就能感触到 Spring 中对于类的设计是如许厉害,代码耦合度非常低。
这些类,在本系列前面的介绍中,大部分都会波及到,当初我先大略介绍一下每个类的作用,大家先混个脸熟:
- BeanFactory:这个接口看名字就晓得是一个 Bean 的工厂,BeanFactory 接口定义了各种获取 Bean 的办法、判断 Bean 是否存在、判断 Bean 是否单例等针对 Bean 的根底办法。
- ListableBeanFactory:这个接口继承自 BeanFactory,在 BeanFactory 的根底上,扩大了 Bean 的查询方法,例如依据类型获取 BeanNames、依据注解获取 BeanNames、依据 Bean 获取注解等。
- AutowireCapableBeanFactory:该接口继承自 BeanFactory,在 BeanFactory 的根底上,提供了 Bean 的创立、配置、注入、销毁等操作。有时候咱们须要本人手动注入 Bean 的时候,能够思考通过实现该接口来实现。AutowireCapableBeanFactory 在 Spring Security 中有一个重要的利用就是 ObjectPostProcessor,这个松哥将在 Spring Security 系列 %26version%3D12031f10%26nettype%3DWIFI%26lang%3Den%26fontScale%3D100%26exportkey%3DA7Vh2vnoyPfiNe4xJBp1Abg%253D%26pass_ticket%3DcsesYv%252BwBmhWaBHD26d%252FJ7tMkuXP0dO73h0sw2UG8l0e1hhkKGiIMjql0rJcXL0r%26winzoom%3D1.000000&uin=&key=&devicetype=iMac+MacBookPro15%2C1+OSX+OSX+10.13.6+build(17G2208)&version=12031f10&lang=en&nettype=WIFI&ascene=0&fontScale=100&winzoom=1.000000) 中和大家具体介绍。
- HierarchicalBeanFactory:该接口继承自 BeanFactory,并在 BeanFactory 根底上增加了获取 parent beanfactory 的办法。
- SingletonBeanRegistry:这个接口定义了对单例 Bean 的定义以及获取办法。
- ConfigurableBeanFactory:这个接口次要定了针对 BeanFactory 的各种配置以及销毁的办法。
- ConfigurableListableBeanFactory:这是 BeanFactory 的配置清单,这里定义了疏忽的类型、接口,通过 Bean 的名称获取 BeanDefinition、解冻 BeanDefinition 等。
- AliasRegistry:这个接口定义了对 alias 的注册、移除、判断以及查问操作。
- SimpleAliasRegistry:这个类实现了 AliasRegistry 接口并实现了它里边的办法,SimpleAliasRegistry 应用 ConcurrentHashMap 做载体,实现了对 alias 的注册、移除判断以及查问操作。
- DefaultSingletonBeanRegistry:这个类基于 Java 中的汇合,对 SingletonBeanRegistry 接口进行了实现。
- FactoryBeanRegistrySupport:该类继承自 DefaultSingletonBeanRegistry,并在 DefaultSingletonBeanRegistry 的根底上,减少了获取 FactoryBean 类型、移除 FactoryBean 缓存的办法等等操作。
- AbstractBeanFactory:实现了 ConfigurableBeanFactory 接口并继承自 FactoryBeanRegistrySupport,在 AbstractBeanFactory 中对 ConfigurableBeanFactory 中定义的办法进行了实现。
- AbstractAutowireCapableBeanFactory:该类继承自 AbstractBeanFactory 并对 AutowireCapableBeanFactory 接口中定义的办法进行了落地实现。
- BeanDefinitionRegistry:这个接口继承自 AliasRegistry 接口,并减少了一系列针对 BeanDefinition 的注册、移除、查问、判断等办法。
- 最初的 DefaultListableBeanFactory 天然就具备了下面所有的性能。
下面的内容可能看的大家目迷五色,松哥这里通过几个简略理论的例子,来带大家应用一下 DefaultListableBeanFactory 的性能,可能大家的了解就比拟清晰了。
DefaultListableBeanFactory 作为一个集大成者,提供了十分多的性能,咱们一个一个来看。
2. 代码革新
首先文章中一开始的三行代码咱们能够对其略加革新,因为咱们曾经说了 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 的性能是不是就很明确了?就是前四行代码的性能。
3. 动静注册 Bean
动静注册 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 接口,并实现了该办法,咱们来看剖析下该办法:
- 首先对传入的 beanDefinition 对象进行校验,这也是注册前的最初一次校验,不过这个时候 BeanDefinition 对象曾经到手了,所以这个校验并非 XML 文件校验,这里次要是对 methodOverrides 的校验。
- 接下来会依据 beanName 从 beanDefinitionMap 中获取 BeanDefinition,看看以后 Bean 是否曾经定义过了。beanDefinitionMap 是一个 Map 汇合,这个汇合中 key 是 beanName,value 是 BeanDefinition 对象。
- 如果 BeanDefinition 曾经存在了,那么接下来会判断是否容许 BeanDefinition 笼罩,如果不容许,就间接抛出异样(不晓得小伙伴们有没有印象,在松哥后面的 OAuth2 系列教程中,常常须要配置容许 BeanDefinition 的笼罩,就是因为这个起因,公众号【江南一点雨】后盾回复 OAuth2 获取该教程),如果容许 BeanDefinition 的笼罩,那就向 beanDefinitionMap 中再次存一次值,笼罩之前的值。
- 如果 BeanDefinition 不存在,那就间接注册。间接注册分两种状况:我的项目曾经运行了和我的项目还没运行。
- 如果我的项目曾经运行,因为 beanDefinitionMap 是一个全局变量,可能存在并发问题,所以要加锁解决。否则就间接注册,所谓的注册就是把对象存入 beanDefinitionMap 中,同时将 beanName 都存入 beanDefinitionNames 汇合中。
这便是 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 入门视频中能够看到成果【https://www.bilibili.com/video/BV1Wv41167TU】,具体原理松哥将在本系列前面的文章中和大家分享。
那么如果不想懒加载该怎么办呢?当然有方法。
4. 提前注册 Bean
在 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 就曾经初始化了,如下图:
5.getBean
DefaultListableBeanFactory 中另外一个重量级办法就是 getBean 了。不过 getBean 办法的真正实现是在 DefaultListableBeanFactory 的父类 AbstractBeanFactory 中,具体的实现办法是 doGetBean,原本想和大家子在这里聊一聊这个问题,然而发现这是一个十分宏大的问题,BeanFactory 和 FactoryBean 都还没和大家分享,所以这个话题咱们还是暂且押后,一个点一个点来。
6. 小结
好啦,明天就先说这么多,每篇源码我都尽量配置套一些小案例来演示,这样防止大家看的太干燥了,咱们下周持续~
如果大家感觉有播种,记得点个在看激励下松哥哦~