Spring——BeanFactory与ApplicationContext

一、BeanFactory

BeanFactory获取bean

public class BeanTest {
    public static void main(String[] args) {
        //创建工厂对象
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        //创建一个读取器,绑定工厂
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);

        //读取配置文件信息
        reader.loadBeanDefinitions("beans.xml");

        //使用工厂 getBean() 方法获取创建的对象
        UserService userService1 = (UserService) beanFactory.getBean("userService");
        System.out.println("userService1 = " + userService1);
        UserService userService2 = beanFactory.getBean(UserService.class);
        System.out.println("userService2 = " + userService2);
        UserService userService3 = beanFactory.getBean("userService", UserService.class);
        System.out.println("userService3 = " + userService3);
    }
}

运行结果:
在这里插入图片描述
BeanFactory 是 Spring 的一个早期接口,称为 Spring 的 Bean 工厂,Bean 创建的主要逻辑和功能都被封装在 BeanFactory 中,这里我们使用的 DefaultListableBeanFactory 是他的一个实现。

BeanFactory 中的 getBean() 方法用于获取创建的对象,其中传递的参数可以是 bean 的名称、bean 的类型,或者两者结合。

从代码运行的结果来看,三种方式获取到的对象都是一个,这是因为默认情况下 Spring 创建的 Bean 对象是单例的。

二、ApplicationContext

上面我们了解了怎么通过 BeanFactory 去创建获取 bean,但是实际的开发中我们不会去使用 BeanFactory 来创建 bean,BeanFactory 是 IoC 容器的基本实现,是 Spring 内部使用的接口,面向 Spring 本身,一般不面向开发人员,不提供开发人员使用。面向 Spring 的使用者,几乎所有场合使用的都是 ApplicationContext。

public class BeanTest {
    public static void main(String[] args) {
        //加载配置文件信息
        ApplicationContext ApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean
        UserDao userDao = (UserDao) classPathXmlApplicationContext.getBean("userDao");
        System.out.println("userDao = " + userDao);
    }
}

ApplicationContext 称为 Spring 容器,内部封装了 BeanFactory,功能比起 BeanFactory 更加丰富强大,使用 ApplicationContext 开发时,配置文件我们习惯命名为 applicationContext.xml

ApplicationContext 本身也是一个接口,这里使用的 ClassPathXmlApplicationContext 是他的实现,用于加载类加载路径下的配置文件

三、两者的继承体系

3.1 BeanFactory

BeanFactory 是 Spring 的核心接口,在项目运行中需要有具体的实现,这个具体的实现就是我们上面使用的 DefaultListableBeanFactory

ApplicationContext 内部会维护一个 BeanFactory,其具体的实现也是 DefaultListableBeanFactory

DefaultListableBeanFactory 中存在两个 map 集合需要我们注意的

  1. beanDefinitionMap:类定义集合
    在这里插入图片描述
    这个集合的内部存储的是类定义的信息
    Java 是面向对象的语言,一切都可以定义为对象,类的定义信息,在 Spring 中也是通过对象来进行存储的
    我们在 xml 中定义的 bean 标签,在项目运行时会被抽取封装为一个个的对象,这些对象对应的类就是 BeanDefinition,BeanDefinition 中会存储我们在 xml 中配置的类的信息,例如类的全类名 beanClass,作用范围 scope 等
    在这里插入图片描述
    通过打断点查看到的 BeanDefinition 的内容

  2. singletonObjects:单例池
    在这里插入图片描述
    准确的说,singletonObjects 并不是 DefaultListableBeanFactory 的属性,而是他的父类 DefaultSingletonBeanRegistry 的属性
    这个 map 是用于存放 Spring 成品 bean 的
    通过打断点看到的 singletonObjects 的内容

Spring 在运行时,大致的步骤是先将 bean 的注册信息存储至 beanDefinitionMap 中,然后再通过遍历 beanDefinitionMap 获取内部的类定义信息,使用工厂和反射来创建对象,再将创建好的对象存储在 singletonObjects 中,之后再获取使用。
在创建对象的过程中,我们可以使用 Spring 提供的后处理器,对 beanDefinitionMap 的内容进行操作,或者在创建好的对象存储进 singletonObjects 之前,对对象进行操作,以达到对 bean 的修改

3.2 ApplicationContext

ApplicationContext,在 Spring 的基础环境下(即只依赖 spring-context 坐标时),ApplicationContext 有三个需要注意的实现类
在这里插入图片描述
ClassPathXmlApplicationContext:适用于加载类路径下的 xml 文件中的类定义信息

AnnotationConfigApplicationContext:适用于加载基于注解定义标记的类的类定义信息

FileSystemXmlApplicationContext:适用于加载文件系统下的 xml 文件中的类定义信息

3.2.1 AnnotationConfigApplicationContext 的使用

ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 都是用于 xml 配置的,主要就是引用配置文件时填写的路径不同,就不需要再演示了,这里我们来说说 AnnotationConfigApplicationContext 的配置方式
AnnotationConfigApplicationContext 是用于加载注解定义标记的类的类定义信息,意思就是我们将 xml 中的 bean 标签,使用 Java 中的注解来代替
代码如下

首先我们要提供一个配置类,这个配置类就相当于我们的 xml 配置文件

public class BeanConfig {
    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }
}

配置类中提供一个方法,方法直接返回我们要的对象,且方法上方需要加上 @Bean 注解,加上这个注解就相当于 xml 中的 bean 标签了

之后在测试类中,我们用 AnnotationConfigApplicationContext 指定配置类

public class BeanTest {
    public static void main(String[] args) {
    	//指定配置类
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        UserDaoImpl userDao = context.getBean("userDao", UserDaoImpl.class);
        System.out.println("userDao = " + userDao);
    }
}

这样就可以实现和 xml 一样的效果了
其中创建的 Bean 的名字,默认就是方法的名称,如果我们需要指定其他的名称,可以使用 @Bean 注解中的value 和 name 属性来指定
在这里插入图片描述
我们后面会学习的其他操作,例如作用域 Scope,也可以通过注解来定义
在这里插入图片描述
如果 bean 中出现了引用其他 bean 的情况,在注解配置的模式下,直接使用 setter 方法注入即可,不过其他的 bean 必须使用方法参数的方式传递进去,不能调用 bean 的方法,否则无法保证单例

方法参数注入:userService 中的 userDao 和 Spring 容器中的 userDao 是同一个对象

public class BeanConfig {
    @Bean
    //将需要注入的参数作为方法的参数传递
    //Spring 在创建 bean 的时候,如果发现需要参数会自动去容器查找,确保了 userDao 的单例
    public UserService userService(UserDao userDao) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }
    
    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }
}

调用 userDao 方法注入:userService 中的 userDao 不是容器中的对象,是调用了 userDao() 方法后新生成的对象

public class BeanConfig {
    @Bean
    //userService 中的 userDao 是调用方法新生成的另一个 userDao
    public UserService userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao());
        return userService;
    }

    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }
}
补充

ApplicationContext 在依赖了其他的 Spring 坐标后,会有更多的实现
依赖了 spring-webmvc 坐标后多出来的实现

四、两者的关系和不同

  1. BeanFactory 是 Spring 的早期接口,称为 Spring 的 Bean 工厂,ApplicationContext 是后期更高级的接口,称为 Spring 容器
  2. ApplicationContext 在 BeanFactory 的基础上对功能进行了扩展,例如监听和国际化功能等。BeanFactory 的 API 更偏向于底层。ApplicationContext 的 API 大多是对这些底层的封装。
  3. Bean 创建的逻辑和功能主要都封装在 BeanFactory中,ApplicationContext 则是继承了 BeanFactory,且 ApplicationContext 内部还维护着 BeanFactory 的引用,所以两者既有继承关系又有融合关系
  4. 两者创建 Bean 的时机不同,BeanFactory 创建 Bean 的时机是在第一次调用 getBean 方法的时候,而 ApplicationContext 默认则是在配置文件加载的时候,容器就将 Bean 都实例化并初始化

继承关系:
在这里插入图片描述
ApplicationContext 是继承了 BeanFactory 的,同时他也继承了像 MessageSource、ResourcePatternResolver 等,相比 BeanFactory 多了更多的功能

融合关系:BeanFactory 是 ApplicationContext 的一个属性
在这里插入图片描述
通过打断点我们可以看到,applicationContext 对象中存在属性 BeanFactory,其实现为 DefaultListableBeanFactory

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值