spring-core-3-26 | Spring IoC容器:BeanFactory和ApplicationContext谁才是Spring IoC容器?

本文深入探讨了Spring IoC容器中的BeanFactory和ApplicationContext的区别。虽然ApplicationContext是BeanFactory的子接口,并添加了更多企业级功能,如AOP整合、国际化支持和事件发布,但它通过组合而非继承的方式来实现BeanFactory的功能。具体来说,ApplicationContext内部持有DefaultListableBeanFactory实例来处理getBean等操作,因此,尽管它们都实现了BeanFactory接口,但它们不是同一个对象。这表明ApplicationContext是对BeanFactory功能的增强和扩展。

Spring IoC 容器

BeanFactory 和ApplicationContext 谁才是Spring IoC 容器?

真正的IOC的底层实现就是BeanFactory的实现类,但ApplicationContext 在底层组合了一个 BeanFactory 实现,是委托DefaultListableBeanFactory来操作getBean等方法的。

也因此
System.out.println(userRepository.getBeanFactory() ==
applicationContext); 是false尽管他们都复用了同样的接口 BeanFactory, 但他们不是一个对象

代码示例

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.ioc.overview.dependency.injection;

import org.geekbang.thinking.in.spring.ioc.overview.repository.UserRepository;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 *
 * 26 | Spring IoC容器:BeanFactory和ApplicationContext谁才是Spring IoC容器?
 * 见下面的 whoIsIoCContainer()
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class DependencyInjectionDemo {

    /**
     * 26 | Spring IoC容器:BeanFactory和ApplicationContext谁才是Spring IoC容器?
     *
     * @param userRepository
     * @param applicationContext
     */
    private static void whoIsIoCContainer(UserRepository userRepository,
                                          //BeanFactory beanFactory
                                          ApplicationContext applicationContext) {
        /*
        ApplicationContext其实就是BeanFactory, 为什么这么说?

        首先要参看spring官方文档对于beanFactory和applicationContext的解释:
        https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/spring-framework-reference/core.html
        1.1节中
        The org.springframework.beans and org.springframework.context packages are the basis
        for Spring Framework’s IoC container.
        org.springframework.beans 和 org.springframework.context是 spring Ioc容器的相关包
        The BeanFactory interface provides an advanced configuration mechanism capable of
        managing any type of object.
        BeanFactory接口提供了一些高级配置的一个机制, 能够来管理任何类型的对象.
        (这里用object, 而不是bean, 是非常准确的, 因为我们前面知道, IoC的依赖来源有bean也有依赖(非bean))
        ApplicationContext is a sub-interface of BeanFactory. It adds:
        ApplicationContext 是 BeanFactory的子接口, 同时还提供了下面的特性:

        Easier integration with Spring’s AOP features
        简化了和spring AOP特性的整合

        Message resource handling (for use in internationalization)
        消息资源的处理(用于国际化)

        Event publication
        事件的发布, 就是spring的事件

        Application-layer specific contexts such as the WebApplicationContext for
        use in web applications.
        用于应用级别的上下文, 比如WebApplicationContext 使用在web场景的应用下

        In short, the BeanFactory provides the configuration framework and basic functionality,
        总而言之, BeanFactory提供了一个配置的框架且是基本的功能
        and the ApplicationContext adds more enterprise-specific functionality.
        并且 ApplicationContext 增加了一些企业级应用的特性.
        到这里我们可以认为BeanFactory就是一个基本的IoC容器, 而ApplicationContext是它的一个超集
        The ApplicationContext is a complete superset of the BeanFactory and is used exclusively
        in this chapter in descriptions of Spring’s IoC container.
        For more information on using the BeanFactory instead of the ApplicationContext, see [beans-beanfactory].
         */


        // 这个表达式为什么不会成立
        System.out.println(userRepository.getBeanFactory() == applicationContext);

        /*
        ApplicationContext is BeanFactory, 如官方文档所说, ApplicationContext就是BeanFactory的一个超集
        我们从子类往上找, 按照这样的方向去找找名堂:
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
        ClassPathXmlApplicationContext => AbstractXmlApplicationContext => AbstractRefreshableConfigApplicationContext
        => AbstractRefreshableApplicationContext => AbstractApplicationContext
        在最后的抽象类 AbstractApplicationContext 中是这样的
        public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
        ConfigurableApplicationContext 是配置模式, 这是一种可写的模式

        在这个类中寻找方法 getBeanFactory()
        @Override
        public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
        可见也是覆盖了接口的方法, 那么这个接口就是 ConfigurableApplicationContext
        那么这里就有些奇怪, 看类头是这样的:
        public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
        ApplicationContext不就是BeanFactory的子接口么
        ConfigurableApplicationContext <- ApplicationContext <- BeanFactory

        这里有两个问题:
        为什么ConfigurableApplicationContext要特意提供一个方法getBeanFactory()? 直接获取不到父类对象么?
        为什么System.out.println(userRepository.getBeanFactory() == applicationContext); 是false呢?

        那么ConfigurableApplicationContext既然是可写模式, 就回提供set方法:
        可以找到
        void setParent(@Nullable ApplicationContext parent);
        但是没有 setBeanFactory??

        往回找到 ConfigurableApplicationContext 的实现类  AbstractApplicationContext 的 getBeanFactory()
        这里就给按层往子类找, 有可能是在中间的抽象类实现的,
        用 ctrl + F12 搜索方法, 会发现实现是放在中间的抽象类 AbstractRefreshableApplicationContext
        @Override
        public final ConfigurableListableBeanFactory getBeanFactory() {
            synchronized (this.beanFactoryMonitor) {
                if (this.beanFactory == null) {
                    throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                            "call 'refresh' before accessing beans via the ApplicationContext");
                }
                return this.beanFactory;
            }
        }

        看一下类中beanFactory变量:
        @Nullable
        private DefaultListableBeanFactory beanFactory;
        会发现这个 beanFactory 是一个组合的, 就是说这里代码是将 beanFactory 的实现 DefaultListableBeanFactory
        来组合进来了, 并不是去完全抽象或继承的这个类.
        那么这也就解释了上面的两个问题
        userRepository.getBeanFactory()获取的也正是 DefaultListableBeanFactory

        这里先提供一个先入为主的概念:
        在上下文里面的实现是采用了一种组合的方式, 同时在接口上面又是 extends 关系
        这种方式有点像代理

        再去看getBean()的实现:
        在 AbstractApplicationContext 中:
        @Override
        public <T> T getBean(Class<T> requiredType) throws BeansException {
            assertBeanFactoryActive();
            return getBeanFactory().getBean(requiredType);
        }
        这里就是先getBeanFactory(), 相当于我们先用代理对象去查找BeanFactory的实现, 并不是自己要具备这样的能力,
        而是外面组装了一个组合对象来帮助我们做这个事情

        结论是
        真正的IOC的底层实现就是BeanFactory的实现类,
        但 ApplicationContext 在底层组合了一个 BeanFactory 实现,
        是委托DefaultListableBeanFactory来操作getBean等方法的。

        也因此 System.out.println(userRepository.getBeanFactory() == applicationContext); 是false
        尽管他们都复用了同样的接口 BeanFactory, 但他们不是一个对象

         */

    }

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值