转载

初窥Spring之容器

前言

先回到《初窥Spring之依赖注入》这篇文章,里面说了,在配置文件中有以下配置:

<bean id="job" class="com.jellythink.Job">
    <!-- 将juniorengineer通过构造函数的方式注入到Job对象中 -->
    <constructor-arg ref="juniorengineer" />
</bean>

在代码中,我们通过 Job job = context.getBean(Job.class); 就可以获得对应的Job类的实例。那么,现在问题来了;仅仅通过一个 getBean 调用就可以获得对应的实例,这是怎么做到的?同时,我们只是get一个Bean,而我们又是从哪里get这个Bean的呢?这篇文章就先来大致说说我们是从哪里获取这个实例对象的。

在基于Spring的应用中,我们的应用对象生存于Spring容器中。Spring容器负责创建对象,配置它们并管理它们的整个生命周期,从生存到死亡。首先最重要的是了解容纳对象的容器。理解容器将有助于理解对象是如何被管理的。

Spring容器并不是只有一个。Spring自带了多个容器实现,可以归为以下两种不同的类型:

  • bean工厂(由 org.springframework. beans. factory.eanFactory 接口定义),是最简单的容器,提供基本的DI 支持;
  • 应用上下文(由 org.springframework.context.ApplicationContext 接口定义)基于BeanFactory构建,并提供应用框架级别的服务,例如 从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者。

由于bean工厂对大多数应用来说往往太低级了,所以我这里只总结应用上下文的使用。

使用应用上下文

Spring自带了多种类型的应用上下文,以下几种是比较常用的:

  • AnnotationConfigApplicationContext :从一个或多个基于Java的配置类中加载Spring应用上下文;
  • AnnotationConfigWebApplicationContext :从一个或多个基于Java的配置类中加载Spring Web应用上下文;
  • ClassPathXmlApplicationContext :从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件 作为类资源;
  • FileSystemXmlapplicationcontext :从文件系统下的一个或多个XML配置文件中加载上下文定义;
  • XmlWebApplicationContext :从Web应用下的一个或多个XML配置文件中加载上下文定义。

其中 AnnotationConfigWebApplicationContextXmlWebApplicationContext 我会在后面的博文会进行详细的总结,这里先说说剩下三种的使用。

无论是从文件系统中装载应用上下文还是从类路径下装载应用上下 文,将bean加载到bean工厂的过程都是相似的。

// 从类路径中加载应用上下文
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("job.xml");

// 从文件系统中加载应用上下文
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("file:/Users/Jelly/job.xml");

这里有篇文章,重点的总结了 Spring中ClassPathXmlApplication和FileSystemXmlApplicationContext使用区别 。

使用 AnnotationConfigApplicationContext 来配置应用上下文则比较麻烦一些,因为要单独编写一个配置类。

对于以下的XML配置来说:

<!-- 创建SeniorEngineer对象 -->
<bean id="seniorengineer" class="com.jellythink.SeniorEngineer" />

<!-- 创建JuniorEngineer对象 -->
<bean id="juniorengineer" class="com.jellythink.JuniorEngineer" />
<bean id="job" class="com.jellythink.Job">
    <!-- 将juniorengineer通过构造函数的方式注入到Job对象中 -->
    <constructor-arg ref="juniorengineer" />
</bean>

则需要编写这样的一个配置类:

@Configuration
public class AppContextDemo {
    @Bean
    public SeniorEngineer seniorengineer() {
        SeniorEngineer seniorengineer = new SeniorEngineer();
        return seniorengineer;
    }

    @Bean
    public JuniorEngineer juniorengineer() {
        JuniorEngineer juniorengineer = new JuniorEngineer();
        return juniorengineer;
    }

    @Bean
    public Job job() {
        JuniorEngineer juniorengineer = new JuniorEngineer();
        Job job = new Job(juniorengineer);
        return job;
    }
}

正如您通过以上代码所看到的那样,现在可以以编程的方式将bean 定义为基于Java的配置的一部分。AppContextDemo类现在就像XML一样表示配置类。这是通过利用@Configuration注释实现的。@Configuration注释位于类的顶端。它告知Spring容器这个类是一个拥有bean定义和依赖项的配置类。@Bean注释用于定义bean。上述注释位于实例化bean并设置依赖项的方法上方。方法名称与bean id或默认名称相同。该方法的返回类型是向Spring应用程序上下文注册的bean。您可使用bean的setter方法来设置依赖项,容器将调用它们来连接相关项。基于Java的配置也被视为基于注释的配置。通过以下代码来使用AnnotationConfigApplicationContext注册配置类:

ApplicationContext context = new AnnotationConfigApplicationContext(AppContextDemo.class);

Bean的生命周期

在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,然后该bean就可以使用了。一旦该bean不再被使用,则由Java自动进行垃圾回收。

相比之下,Spring容器中的bean的生命周期就显得相对复杂多了。正确理解Spring bean的生命周期非常重要,因为将来我们可能要利用Spring提供的扩展点来自定义bean的创建过程。下面先通过一张图来说明bean的整个生命周期。

初窥Spring之容器

从上图中可以看到,在bean准备就绪之前,bean工厂执行了若干启动步骤。下面就对上面的每一步都进行简单的说明:

  1. Spring对bean进行实例化;
  2. Spring将值和bean的引用注入到bean对应的属性中;
  3. 如果bean实现了 BeanNameAware 接口,Spring将bean的ID传递给setBean-Name()方法;
  4. 如果bean实现了 BeanFactoryAware 接口,Spring将调用 setBeanFactory() 方法,将BeanFactory容器实例传入;
  5. 如果bean实现了 ApplicationContextAware 接口,Spring将调用 setApplicationContext() 方法,将bean所在的应用上下文的 引用传入进来;
  6. 如果bean实现了 BeanPostProcessor 接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
  7. 如果bean实现了 InitializingBean 接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用init- method声明了初始化方法,该方法也会被调用;
  8. 如果bean实现了 BeanPostProcessor 接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
  9. 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
  10. 如果bean实现了 DisposableBean 接口,Spring将调用它的 destroy() 接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

上面就是一个bean在Spring容器中的整个生命周期。每一阶段都可以针对Spring如何管理bean进行个性化定制,这个就可以根据我们的需要来搞了。

总结

Spring容器这个概念贯穿着整个Spring,我们必须要掌握的知识点,这篇文章也只是总结了一点皮毛,但是对于入门Spring容器还是有很大帮助的,希望大家喜欢。

无聊而有趣的一天,虚度而又充实的一个周末。

果冻想-一个原创技术文章分享网站。

2017年6月4日 于呼和浩特。

原文  http://www.jellythink.com/archives/1556
正文到此结束
Loading...