Spring Framework—2、ApplicationContext

ApplicationContext接口

spring framework最主要的功能之一就是IoC(Inversion of Control)容器。Spring IoC容器负责管理一个应用程序中的所有对象。它用依赖注入来实现控制反转。

BeanFactory和ApplicationContext这两个接口代表了spring IoC容器。此时,BeanFactory是访问spring容器的最根本的接口。它提供管理Bean的最基础功能。

另一方面,ApplicationContext是BeanFactory的一个子接口。因此它提供BeanFactory的所有功能。

此外,它提供了更多的特定的企业级功能。ApplicationContext实现的功能包括:消息处理、支持国际化、发布事件、以及应用层特定的上下文。这就是为什么我们把它作为默认的spring容器的原因。

什么是spring Bean

首先我们需要深入研究这个ApplicationContext容器,它对于理解spring Bean是很重要的。在spring中,bean就是一个被spring容器初始化、装配和管理的对象。

那么,我们应该把所有的应用程序中的对象都配置成spring bean吗?作好更佳实践,我们不推荐这样做。

根据spring文档,我应该将服务层对象定义为bean,数据访问对象(DAOs)、表示层对象、基础框架对象,例如Hibernate的SessionFactories、JMS队列等等。

通常我们不应该在容器中配置细粒度的领域对象。创建和加载领域对象通常是DAO和业务逻辑的责任。

现在,我们定义一个简单的spring bean(这是一个Service的层的spring bean),如下:

public class AccountService {

  @Autowired
  private AccountRepository accountRepository;

  // getters and setters
}

配置容器中的bean

我们知道,ApplicationContext的主要工作就是管理Bean。

正因为如此,应用程序必须为ApplicationContext容器提供bean的配置。一个Spring Bean的配置是由一个或多个Bean定义构成的,Spring支持不同的方式配置Bean。

1、基于Java的配置

首先,我们从基于Java的配置开始,因为它是最新的,也是更受欢迎的Bean配置方式。它是从Spring3.0开始启用的。

java配置通常是用一个@Configuration类注解中的@Bean注解其中的方法。这个@Bean注解在一个方法上,指明这个方法创建一个Spring Bean。此外,类使用@Configuration注解,表明它包含spring bean配置。

创建示例如下:

(1)、定义一个功能类,用于提供对外生成UUID

public class HelloUtils {
    public String getUUID(){
        return UUID.randomUUID().toString();
    }
}

(2)、定义一个bean的配置类

@Configuration
public class UtilsConfiguration {

    @Bean
    public HelloUtils getHelloUtilsService(){
        return new HelloUtils();
    }
}

(3)、生成调用代码,测试依赖注入

public class HelloApplication {

    public HelloApplication(){
        ApplicationContext context = 
                new AnnotationConfigApplicationContext(UtilsConfiguration.class);
        HelloUtils helloUtils = context.getBean(HelloUtils.class);
        System.out.println(helloUtils.getUUID());
    }

    public static void main(String[] args) {
        new HelloApplication();
    }
}

2、基于注解的配置

Spring2.5引入的基于注解的配置,作为在java中开启bean配置的第一步。在这个方法中,我们首先通过XML配置来启用基于注解的配置。然后,我们使用一组注解在类、方法、构造成上或者字段上来配置bean。这些注解中的一些示例,如@Component、@Controller、@Service、@Repository、@Autowired和@Qualifier。

值得注意的是,我们也在基于java的配置中使用这些注解。还值得一提的是,Spring每一个版本都持续在这些注解中添加新功能。

现在我们看一个简单的例子:

(1)、编写一个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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <!-- 这里的包名请换成自己的工程中,需要使用spring IoC容器管理的包名 -->
    <context:component-scan base-package="com.dokbok.hsfw"/>

</beans>

(2)、编写测试类

public class HelloApplication {

    public HelloApplication(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");

        HelloUtils helloUtils = ctx.getBean(HelloUtils.class);
        System.out.println(helloUtils.getUUID());
    }

    public static void main(String[] args) {
        new HelloApplication();
    }
}

3、基于XML的配置

最后,让我们来看一看基于XML的配置。这是Spring中传统的配置bean的方式。

显然的,用这个方法,我们在一个XML配置文件中执行所有bean的映射。示例如下:

(1)、编写配置文件

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="helloUtils" class="com.dokbok.hsfw.utils.HelloUtils"></bean>

</beans>

(2)、编写测试类

public class HelloApplication {

    public HelloApplication(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");

        
        //使用bean的Id查找bean的对象
        HelloUtils helloUtils = (HelloUtils) ctx.getBean("helloUtils");
        System.out.println(helloUtils.getUUID());
    }

    public static void main(String[] args) {
        new HelloApplication();
    }
}

ApplicationContext的类型

Spring为不同的需求提供了不同的ApplicationContext容器与之适配。这些容器都实现了ApplicationContext的接口。

1、AnnotationConfigApplicationContext

首先,让我们看AnnotationConfigApplicationContext类,它是从spring3.0开始引入的。它可以接受用@Configuration、@Component注解的类和JSR-330数据作为输入。

示例同基于Java的配置,只需要将其中UtilConfiguration类中的@Configuration注解更换成@Component(如果你想测试@Component能不能工作的话)即可。

//注意:@Configuration注解可以更换成@Component注解也可以
@Configuration
public class UtilsConfiguration {

    @Bean
    public HelloUtils getHelloUtilsService(){
        return new HelloUtils();
    }
}

2、AnnotationConfigWebApplicationContext

AnnotationConfigWebApplicationContext是一个基于AnnotationConfigApplicationContext的一个变种。当我们需要配置Spring的ContextLoaderListener Servlet监听器,或者在web.xml文件中配置Spring MVC的DispatchServlet时使用这个注解类。

此外,自从Spring3.0开始,我们也可以以编程的方式配置应用程序的上下文容器。我们需要做的全部就是实现WebApplicationInitializer接口。

public class MyWebApplicationInitializer implements WebApplicationInitializer {

  public void onStartup(ServletContext container) throws ServletException {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.register(AccountConfig.class);
    context.setServletContext(container);

    // servlet configuration
  }
}

3、XmlWebApplicationContext

如果我们想在一个Web应用程序中使用基于XML的配置,我可以使用XmlWebApplicationContext类。

事实上,使用这个类配置容器就像AnnotationConfigApplicationContext类一样,意味着你可以在web.xml中配置它,或者实现WebApplicationInitializer接口。

public class MyXmlWebApplicationInitializer implements WebApplicationInitializer {

  public void onStartup(ServletContext container) throws ServletException {
    XmlWebApplicationContext context = new XmlWebApplicationContext();
    context.setConfigLocation("/WEB-INF/spring/applicationContext.xml");
    context.setServletContext(container);

    // Servlet configuration
  }
}

4、FileSystemXmlApplicationContext

我们使用FileSystemXmlApplicationContext类从文件系统或者URL地址加载一个基于Xml的spring配置。当我们需要以编程的方式加载ApplicationContext的时候,我们可以使用它。通常,测试框架和独立的应用程序是一些可能的使用场景。

String path = "C:/myProject/src/main/resources/applicationcontext/account-bean-config.xml";

ApplicationContext context = new FileSystemXmlApplicationContext(path);
AccountService accountService = context.getBean("accountService", AccountService.class);

5、ClassPathXmlApplicationContext

万一我们想从classpath加载一个XML配置文件,我可以使用ClassPathXmlApplicationContext类。和FileSystemXmlApplicationContext类似,他常用于测试框架,以及嵌入到JAR中的应用程序上下文。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/account-bean-config.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);

ApplicationContext的附加功能

1、消息处理

ApplicationContext接口通过扩展MessageSource接口支持消息处理和国际化。此外,srping提供两个消息资源的实现,ResourceBundleMessageSource和StaticMessageSource。

我们可以使用StaticMessageSource以编程的方式添加消息到源。然而,它支持基本的国际化,更适合于测试而不是生产。

另一方面,ResourceBundleMessageSource是MessageSource最常见的实现。它依赖底层的JDK的ResourceBundle实现。它也使用由MessageFormat提供的JDK的标准消息解析。

示例:

方法一:

(1)、在classpath中定义资源文件

内容如下:

myName=tdjgamtam

(2)、编写spring bean配置

    @Bean
    public ResourceBundleMessageSource getMessageSource(){
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("config/message");
        return messageSource;
    }

(2)、编写测试代码

public class HelloApplication {

    public HelloApplication(){
        ResourceBundleMessageSource messageSource =
                ctx.getBean(ResourceBundleMessageSource.class);

        String myName = 
                messageSource.getMessage("myName",null,"default", Locale.CHINA);
        System.out.println(Locale.getDefault());
    }

    public static void main(String[] args) {
        new HelloApplication();
    }
}

Spring也提供了ReloadableResourceBundleMessageSource类,允许从spring的资源目录读取文件,并且支持热加载绑定的属性文件。

方法二:

(1)、只需要定义相关的资源文件及填写入内容(src/main/resources/message_zh_CN.properties)

myName=tdjgamtam

(2)、直接使用ApplicationContext来获取资源信息

由于ApplicationContext实现了MessageResource接口,所以可以直接使用ApplicationContext对象来直接获取资源文件中的消息。

public class HelloApplication {

    public HelloApplication(){
        ApplicationContext ctx = 
                new AnnotationConfigApplicationContext(UtilsConfiguration.class);

        String myName =
                ctx.getMessage("myName",null,"default", Locale.CHINA);
        System.out.println(Locale.getDefault());
    }

    public static void main(String[] args) {
        new HelloApplication();
    }

}

2、事件处理

在ApplicationEvent类和ApplicationListener接口的帮助下,ApplicationContext也支持事件处理。它支持内嵌事件,比如ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent和RequestHandledEvent,此外,它也支持用于业务用例的自定义事件。

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注