1.DefaultListableBeanFactory

创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站建设、做网站、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的怀安网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
要说 XmlBeanFactory 就不得不先说它的父类 DefaultListableBeanFactory,因为 XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了,XmlBeanFactory 只是对 IO 流的读取做了一些定制而已。
DefaultListableBeanFactory 是一个完整的、功能成熟的 IoC 容器,如果你的需求很简单,甚至可以直接使用 DefaultListableBeanFactory,如果你的需求比较复杂,那么通过扩展 DefaultListableBeanFactory 的功能也可以达到,可以说 DefaultListableBeanFactory 是整个 Spring IoC 容器的始祖。
我们先来看一下 DefaultListableBeanFactory 的继承关系:
从这张类的关系图中可以看出,DefaultListableBeanFactory 实际上也是一个集大成者。在 Spring 中,针对 Bean 的不同操作都有不同的接口进行规范,每个接口都有自己对应的实现,最终在 DefaultListableBeanFactory 中将所有的实现汇聚到一起。从这张类的继承关系图中我们大概就能感受到 Spring 中关于类的设计是多么厉害,代码耦合度非常低。
这些类,在本系列后面的介绍中,大部分都会涉及到,现在我先大概介绍一下每个类的作用,大家先混个脸熟:
上面的内容可能看的大家眼花缭乱,松哥这里通过几个简单实际的例子,来带大家使用一下 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
 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 入门视频中可以看到效果【??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
 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
 ) - ((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
 - 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.小结
好啦,今天就先说这么多,每篇源码我都尽量配置套一些小案例来演示,这样避免大家看的太枯燥了,我们下周继续~
本文转载自微信公众号「江南一点雨 」,可以通过以下二维码关注。转载本文请联系江南一点雨公众号。
                分享文章:聊聊容器的始祖DefaultListableBeanFactory
                
                网页URL:http://www.csdahua.cn/qtweb/news14/212114.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网