Spring学习之IOC容器BeanFactory和ApplicationContext(三)

Spring 提供了以下两种不同类型的容器,BeanFactory和ApplicationContext。

  • Spring BeanFactory 容器

    这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。 BeanFactory 和相关的接口,比如,BeanFactoryAware、 DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。

    在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类,但在Spring3.2中已被废弃,建议使用XmlBeanDefinitionReader,DefaultListableBeanFactory替代。

  • BeanFactory的类体系结构

    BeanFactory的类继承体系设计优雅,堪称经典,通过继承体系,我们可以容易了解到BeanFactory具有哪些功能。

    这里写图片描述

    BeanFactory接口位于类结构树的顶端,它最主要的方法就是getBean(String beanName),该方法从容器中返回特定名称的Bean。BeanFactory的功能通过其他接口得到不断扩展。

    • ListableBeanFactory:该接口定义了访问容器中Bean基本信息的若干方法,如查看Bean的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等。

    • HierarchicalBeanFactory:父子级联IOC容器的接口,子容器可以通过接口方法访问父容器。

    • ConfigurableBeanFactory:这是一个重要的接口,增强了Ioc容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法。

    • AutoWireCapableBeanFactory:定义了将容器中的Bean按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法。

    • SingletonBeanFactory:定义了允许在运行期间向容器注册单实例Bean的方法。

    • BeanDefinitionRegistry:Spring配置文件中每一个<bean> 节点元素在Spring容器里都通过一个BeanDefinition对象表示,它描述了Bean的配置信息。而BeanDefinition Registry接口提供了向容器手工注册BeanDefinition对象的方法。

  • 初始化BeanFactory

    bean.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    <bean id="helloWorld" class="com.yf.HelloWorld"
        p:message="Hello world!"/>
    </beans>

    HelloWorld类:

    public class HelloWorld {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    public void getMessage() {
        System.out.println("Your Message : " + message);
    }
    }

    BeanFactoryTest#getBeanTest():

    
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource resource = resolver.getResource("classpath:bean.xml");
        System.out.println(resource.getURI());
    
        // 在3.2被废弃,不建议使用
        // BeanFactory bf = new XmlBeanFactory(resource);
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);
    
        System.out.println("init BeanFactory");
    
        HelloWorld hello = factory.getBean("helloWorld", HelloWorld.class);
        System.out.println("helloWorld bean is ready for use");
        hello.getMessage();
    

    XmlBeanDefinitionReader通过Resource装载Spring配置信息并启动Ioc容器,然后就可以通过BeanFactory#getBean(beanName)方法从Ioc容器中获取Bean。通过BeanFactory启动Ioc容器时,并不会初始化配置文件中定义的Bean,初始化动作发生在第一个调用时,对于实例(singleton)的Bean来说,BeanFactory会缓存Bean实例,所以第二次使用getBean()获取Bean时,将直接从Ioc容器的缓存中获取Bean实例。

    Spring的DefaultSingletonBeanRegistry类中提供了一个用于缓存单实例Bean的缓存器,它是一个用HashMap实现的缓存器,单实例的Bean以beanName为键保存在这个HashMap中。

    值得一提的是,在初始化BeanFactory时,必须为其提供一种日志框架,我们使用Log4J,即在类路径下提供Log4J配置文件,这样启动Spring容器才不会报错。

  • ApplicationContext

    如果说BeanFactory是Spring的“心脏”,那么ApplicationContext就是完整的“身躯”了,ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能,在BeanFactory中,很多功能需要以编程的方式实现,而在ApplicationContext中则可以通过配置的方式实现。

  • ApplicationContext类体系结构

    ApplicationContext主要实现类是 ClassPahXmlApplicationContext FiIeSystemXmlApplicationContext,前者默认从类路径加我配置文件,后者默认从文件系 统中装载配置文件。下面了解一下ApplicationContext的类继承休系,如图所示。

    这里写图片描述

    从图中可以看出,ApplicationContext继承了HierarchicalBeanFactory和 ListableBeanFactory接口,在此基础上,还通过多个其他的接口扩展了BeanFactory的功能。这些接口如下。

    • ApplicationEventPublisher:让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。实现了ApplicationListener事件监听接口的Bean可以 接收到容器事件,并对事件进行响应处理。在ApplicationContext抽象实现类 肋AbstractApplicationContext中存在一个ApplicationEventMulticaster,它负责保存所有的监听器,以便在容器产生上下文事件时通知这些事件监听者。

    • MessageSource: 为应用提供i18n国际化消息访问的功能。

    • ResourcePatterResolver:所有ApplicationContext实现类都实现了类似干 PathMatchingResourcePatternResolver的功能,可以通过带前缀的Ant风格的资 源文件路径装载Sping的配置文件。

    • LifeCycle:该接口提供了start()和stop()两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被ApplicationContext实现及具体Bean实现, ApplicationContext会将start/stop的信息传递给容器中所有实现了该接口的 Bean,以达到管理和控制JMX、任务调度等目的。

    • ConfigurableApplicationContext扩展于ApplicationContext,它新增了两个主要的方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。在应用上下文关闭的情况相下调用refresh()即可启动应用上下文,在已经启动的状态下调用refresh()则可清除缓存并重新装载配置信息,而调用close()则可关闭应用上下文。这些接口方法为容器的控制管理带来了便利,但作为开发者,并不需要过多关心这些方法。

  • ApplicationContext初始化

    和BeanFactory初始化相似,ApplicationContext的初始化也很简单,如果配置文件在类路径下,则可优先考虑使用ClassPathXmlApplicationContext实现类

    ApplicationContext ctx = new ClassPathXmlApplicationContext("com/yf/context/beans.xml");

    对于ClassPathXmlApplicationContext来说,”com/yf/context/beans.xml”等同于”classpath:com/yf/context/beans.xml”。
    如果配置文件在文件系统的路径下,则可优先考虑使用FileSystemXmlApplicationContext实现类

    ApplicationContext ctx = new FileSystemXmlApplicationContext("com/yf/context/beans.xml");

    对于FileSystemXmlApplicationContext来说,”com/yf/context/beans.xml”等同于”file:com/yf/context/beans.xml”。
    还可以指定一组配置文件,Spring会自动将多个配置文件在内存“整合”成一个配置文件:

    ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"conf/beans1.xml","conf/beans2.xml"});

    当然,FileSystemXmlApplicationContext和ClassPathXmlApplicationContext都可以显式使用带资源类型前缀的路径,它们的区别在于如果不显式指定资源类型前缀,则分别将路径解析为文件系统路径和类路径。

    在获取ApplicationContext实例后,就可以像BeanFactory一样调用 getBean(beanName)返回Bean了。ApplicationContext的初始化和BeanFactory宥一个重大的区别:BeanFactory 在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例化目标Bean; 而ApplicationContext则在初始化应用上下文吋就实例化所有单实例的Bean。因此ApplicationContext的初始化时间会比BeanFactory稍长一些,不过稍后的调用则没有“第 一次惩罚”的问题。

    Spring支持基于类注解的配置方式,主要功能来自Spring的一个名为JavaConfig的子项目。JavaConfig现已升级为Spring核心框架的一部分。一个标注@Configuration注解的POJO即可提供Spring所需的Bean配置信息。
    实例:
    带注解的JAVA类提供的配置信息

//这是一个配置信息提供类
@Configuration
public class Beans {
    // 定义一个Bean
    @Bean(name = "helloWorld")
    public HelloWorld bulidHello() {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.setMessage("hello world");
        return helloWorld;
    }

}

通过带@Configuration的配置类启动容器

public class AnnotationApplicationContextTest {
    @Test
    public void getBean() {
        // 通过一个带@Configuration的POJO装载Bean配置
        ApplicationContext context = new AnnotationConfigApplicationContext(Beans.class);
        HelloWorld hw = context.getBean("helloWorld", HelloWorld.class);
        hw.getMessage();
    }

}

AnnotationConfigApplicationContext将加载Bean.class中的Bean定义并调用Bean.class中的方法实例化Bean,启动容器并装配Bean。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值