org.springframework.context.ApplicationContext 代表 Spring IoC 容器,并负责实例化,配置和组装上述 bean 。容器通过读取配置元数据获得哪些对象需要实例化、配置和组装的指定。配置元数据可以在XML、Java注解和Java代码中配置。它运行你描述组成你应用程序的对象和对象之间复杂的关系。
Spring提供了一些开箱即用的ApplicationContext接口的实现。在独立的应用程序中,一般可以创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。虽然XML一直是传统的定义配置元数据的格式,但也可以指示容器使用Java注解或者代码作为元数据的格式,并提供少量的XML配置以声明的方式启用这些额外的元数据格式的支持。
在大多数的应用场景,用户代码并不需要明确的实例化一个或多个Spring IoC容器的实例。例如,在web应用场景中,程序的web.xml文件中定义一个8行左右的web部署描述符XML就可以满足要求。如果使用的是基于Eclipse的 Spring Tool Suite开发环境,该配置可以很容易地用敲几下鼠标或键盘创建。
下图是展示 Spring 如何工作的高级视图。应用程序的类与配置元数据进行结合,以便在 ApplicationContext创建和初始化后,拥有一个完全配置和可执行的系统或应用程序。
1 配置元数据
如上述图所示,Spring IoC 容器使用配置元数据;这个配置元数据代表了应用程序开发人员告诉 Spring 容器在应用程序中如何来实例化,配置和组装对象。
传统的配置元数据是一个简单而直观的 XML 格式。
基于 XML 的元数据并不是配置元数据的唯一允许的形式。 Spring IoC容器本身是完全与配置元数据的实际写入格式分离的。现在,许多开发人员选择基于 Java 的配置来开发他们的应用程序。
其他格式的元数据:
- 基于注解的配置:Spring 2.5 的推出了基于注解的配置元数据支持;
- 基于Java的配置:Spring3.0 开始,由 Spring JavaConfig 项目提供的很多功能成为核心 Spring 框架的一部分。因此,可以通过使用Java,而不是 XML 文件中定义外部 bean 到你的应用程序类。要使用这些新功能,参阅 @Configuration,, 和 @DependsOn 注解。
Spring 配置至少一个、通常不止一个 bean 由容器来管理。基于 XML 的配置元数据将这些 bean 配置为<bean/>元素,并放置到<beans/> 元素内部。 Java 配置通常在 @Configuration注解的类中使用 @Bean 注解的方法。
这些bean定义对应组成应用程序的实际对象。通常会定义服务层对象,数据访问对象(DAO),展示对象,例如Structs Action实例,基础设施的对象,如 Hibernate 的 SessionFactories,JMS Queues等等。通常,在容器中不配置细粒度的域对象,因为通常由DAO和业务逻辑负责创建和加载域对象(这里的域对象应该类似于POJO)。但是你可以使用 Spring 和 AspectJ的集成配置在 IoC 容器的控制之外创建的对象。
以下示例显示基于 XML 的配置元数据的基本结构:
id 属性是一个字符串,唯一识别一个独立的 bean 定义。class 属性定义了 bean 的类型,使用完整的类名。 id 属性的值指向协作对象。在XML 配置协作对象未在本例中示给出(关于协作对象这句,应该是指在依赖关系的引用时使用id属性,这个例子并没有给出依赖关系的引用)。
2 实例化容器
实例化 Spring IoC 容器是简单的。提供给ApplicationContext构造函数的位置路径实际上是容器从各种外部资源(如本地文件系统、Java ClassPath等)加载配置元数据的资源字符串。
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
当了解了Spring IoC容器后,由必要了解Spring Resource抽象概念,它提供了一种便捷的机制从uri语法定义的位置读取InputStream。通常,Resource路径用于构造应用上下文。
下面的例子展示了业务层对象(services.xml)的配置文件:
下面的例子展示数据接入层(daos.xml)的配置文件:
上面的例子中,业务层包含了PetStoreServiceImpl类和两个类型为JpaAccountDao和JpaItemDao数据接入对象(基于JPA对象/关系映射标准)。property元素的 name 属性是指 JavaBean 属性的名称,而 ref 属性引用另一个 bean 定义的名称。 id 和 ref 元素之间的这种联系表达了协作对象之间的依赖关系。
撰写基于XML的配置元数据
bean的定义跨越多个XML文件是有用的。一般一个XML配置文件代表程序架构中的一个业务层或业务模块。
可以使用应用上下文的构造函数从所有XML段中加载bean定义。构造函数加载多个Resource地址,正如上文的例子那样。另一种方法,可以使用一个或多个<import/>元素从其它文件中加载bean定义。例如:
上例中,从三个文件中加载外部的bean定义:services.xml,messageSource.xml和themeSource.xml。所有的位置路径都相对于导入文件的路径,因此services.xml必须位于导入它的文件的相同文件夹或类路径,而messageSource.xml和themeSource.xml需位于导入它们的文件路径的resources下。前面的斜线可以被忽略,但考虑到这些路径是相对的,最好不使用斜线。被导入的文件(要包含顶级元素<beans/>),必须是有效的bean定义(根据Spring Schema)。
使用相对路径../是可行的,但是并不推荐。这样做会对当前应用程序之外的文件产生依赖。一般情况下,这种相对路径并不推荐用于classpach:URLs的格式(例如,classpath: ../services.xml),运行时解析进程选择最近的classpath根目录然后查找它的父文件夹。classpath配置改变也许会导致选择了一个不同的、错误的文件夹。
应该总是使用绝对路径代替相对路径:例如"file:C:/config/services.xml"或者"classpath:/config/services.xml"。然而,应当注意这样应用程序就和特定的绝对路径耦合了。所以通常使用间接的方式应对这种绝对路径,例如使用在JVM系统运行时解析的占位符${...}。
XML文件中的import指令是由beans的命名空间本身提供的功能。不在beans命名空间中的更多配置功能由Spring的可选命名空间提供,例如context和util命名空间。
Groovy Bean Definition DSL
作为外部配置元数据的进一步例子,bean定义可以使用Spring的Groovy Bean Definition DSL(来自Grails框架)表示。一般的,这种配置保存在.groovy文件中并有如下的格式:
beans { dataSource(BasicDataSource) { driverClassName = "org.hsqldb.jdbcDriver" url = "jdbc:hsqldb:mem:grailsDB" username = "sa" password = "" settings = [mynew:"setting"] } sessionFactory(SessionFactory) { dataSource = dataSource } myService(MyService) { nestedBean = { AnotherBean bean -> dataSource = dataSource } }}
这种配置风格在很大程度上等同于XML bean定义,甚至支持Spring XML配置的命名空间。它还允许通过“importBeans”指令导入XML bean定义文件。
3 使用容器
ApplicationContext是拥有注册不同bean和它们之间依赖关系的高级工厂接口。使用方法 T getBean(String name, Class requiredType)就可以获取 bean 的实例。
ApplicationContext可以使你按如下方法读取bean定义并获取它们:
// create and configure beansApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");// retrieve configured instancePetStoreService service = context.getBean("petStore", PetStoreService.class);// use configured instanceListuserList = service.getUsernameList();
使用Groovy配置的启动方式类似,仅仅是使用理解Groovy的context实现类(这个类依然能够识别XML的bean定义):
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
最灵活的方式是将GenericApplicationContext类与reader代理一起使用,例如读取XML文件的XmlBeanDefinitionReader:
GenericApplicationContext context = new GenericApplicationContext();new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");context.refresh();
或者读取Groovy文件的GroovyBeanDefinitionReader:
GenericApplicationContext context = new GenericApplicationContext();new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");context.refresh();
如果需要这些reader代理可以和同一ApplicationContext混合使用,从不同的配置源读取bean定义。
可以使用 getBean() 方法来获取 bean 的实例。 ApplicationContext 接口有一些其他的方法来获取 bean,但理想的应用程序代码不应该使用它们。事实上,你的应用程序代码不应该调用的getBean() 方法,因此不会产生对 Spring 的 API 依赖性的。例如,Spring与web框架集成,为web框架组件例如(controllers、JSF管理bean)提供依赖注入,允许你通过元数据为特殊的bean声明依赖关系。