核心技术
版本 5.2.4.RELEASE
参考文档的这一部分涵盖了Spring框架中不可获取的所有技术
其中最重要的是Spring的ioc(控制反转)容器,在对SpringIOC进行了全面的处理之后,还对SpringAOP技术进行了全面的介绍。Spring框架有它自己的AOP框架,并且在概念上容易理解,成功的解决了Java企业编程中AOP需求的80%功能点。
Spring还提供了对AspectJ的支持。
1 IOC容器
这一章覆盖了SpringIOC容器
1.1 介绍SpringIOC容器和bean
这一章覆盖了Spring框架实现了IOC容器的原理。IOC也成为依赖注入(DI)。这是一个对象仅通过构造函数参数、工厂方法的参数或对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即与之一起工作的其他对象)的过程。然后容器在创建bean时注入这些依赖项。这个过程基本上是bean本身的逆过程(因此成为控制反转),通过使用类的直接构造或一种机制(如服务定位器模式)来控制依赖项的实例化或位置。
这org.springframework.beans
和org.springframework.context包是SpringIOC容器的基础。BenaFactory接口提供了能够管理任何类型对象的高级配置机制。ApplicationContext是BeanFactory的子接口。它增加了:
- 更容易与SpringAOP特性集成
- 消息资源处理(用于国际化)
- 事件发布
- 特定于应用程序层的上下文,如web应用程序中使用的WebApplicationContext
简而言之,BeanFactory提供了配置框架和基本功能,而ApplicationContext添加了更多企业特定的功能。ApplicationContext是BeanFactory的一个完成功能的实现者,在本章描述SpringIoC容器时专门使用它。有关于使用BeanFactory而不是ApplicationContext的更多信息,请参见BeanFactory。
在Spring中,构成应用程序主干并由SpringIoC容器管理的对象称为bean。bean是由SpringIoC容器实例化、组装和管理的对象。否则、bean只是应用程序中众多对象之一。bean及其之间的依赖关系反映在容器使用的配置元数据中。
1.2 容器概述
org.springframework.context.ApplicationContext
接口表示SpringIoC容器,负责实例化、配置和组装bean。容器通过读取配置元数据获取关于要实例化、配置和组装那些对象的指令。配置元数据用XML、Java注解、Java代码等方式。它允许你表达组成应用程序的对象及这些对象之间丰富的相互依赖关系。
ApplicationContext接口的几个实现由Spring提供。在独立应用程序中,通常会创建ClassPathXmlApplicationContex或FileSystemXmlApplicationContext实例。虽然XML一直是定义配置元数据的传统格式,但是可以通过提供少量XML配置以声明的方式支持这些额外的元数据格式,从而指示容器使用Java注解或代码作为元数据格式。
在大多数应用程序场景中,不需要显示的用户代码来实例化一个或者多个SpringIoC容器实例。例如,在web应用程序场景中,在应用程序的web.xml文件中使用大约8行简单的样板web描述符xml通常就足够了。如果你使用spring工作套件,那么只需要几次鼠标单击,就可以轻松地创建这个样板配置。
下图显示了Spring如何工作的高级视图。你的应用程序类与配置元数据结合,这样,在创建并初始化ApplicationContext之后,你就拥有了一个完全配置和可执行化的系统或应用程序。
图1所示 SpringIoC容器
1.2.1 配置元数据
如上图所示,SpringIoC容器使用配置元数据的一种形式。此配置元数据表示作为应用程序开发人员,你如何告诉Spring容器实例化、配置和组装应用程序中的对象。
配置元数据通常以简单直观的XML格式提供,本章大部分内容都是使用这种格式来传达SpringIoC容器的关键概念和特性。
基于xml的元数据不是唯一允许的配置元数据形式。SpringIoC容器本身与实际编写配置元数据的格式完全解耦。现在,许多开发人员为他们的Spring应用程序选择继续Java的配置。 |
有关在Spring容器中使用其他形式的元数据的信息,请参阅:
- 基于注解的配置 :Spring 2.5引入了对基于注释的配置元数据的支持。
- 基于java配置:从Spring3.0开始,Spring JavaConfig项目提供的许多特性称为Spring核心框架的一部分。因此,你可以使用Java而不是XML文件来定义应用程序类外部的bean。而要使用这些特性,请参见@Congiguration、@Be'an、@Improt和@DependsOn注解。
Spring配置由容器必须管理的至少一个和通常多个bean定义组成。基于xml的配置元数据将这些bean配置为顶级的<beans/>元素中的<bean/>元素。Java配置通常在@Configuration类中使用@bean注解的方法。
这些bean定义应用于组成应用程序的实际对象。通常,你要定义服务层对象、数据访问对象(DAOs)、表示对象(如Struts Action实例)、基础设置对象(Hibernate SessionFactories)、JMS队列等等。通常,不会在容器中配置细粒度域对象,因为通常由DAOs和业务逻辑负责创建和加载域对象。但是,你可以使用Spring与AspectJ的集成来配置在空间之外的创建的对象。
下面离职展示了基于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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
- id属性是标识单个bean定义的字符串
- class属性定义bean的类型并使用完全限定的类名
id属性的值引用协作对象。本例中没有显示用于引用协作对象的xml。有关更多信息,请参见依赖项。
1.2.2 实例化一个容器
提供给ApplicationContext构造函数的位置路径是资源字符串,它允许容器从各种外部资源(如本地文件系统、Java类路径等)装载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
在了解了Spring的IoC容器之后,你可能想了解更多关于Spring的资源抽象的信息,它提供了一种方便机制,用于从URI语法中定义的位置读取InputStream。特别是,资源路径用于构造应用程序上下文,如应用程序上下文和资源路径中所述。 |
下面的实例显示了服务层对象(services.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
下面的例子展示了数据访问daos.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
在前面的实例中,服务层由PetStoreServiceImpl类和JpaAccountDao和JpaItemDao类型的两个数据访问对象(基于JPA对象-关系映射标准)组成。property name元素引用JavaBean属性的名称,而ref元素引用另一个bean定义的名称。id和ref元素之间的这种链接表达了协作对象之间的依赖关系。有关配置对象依赖项的详细信息,请参阅依赖项。
组合基于XML的配置元数据
让bean定义跨越多个XML文件可能很有用。通常,每个单独的XML配置文件表示体系结构的逻辑层或模块。
让bean定义跨越多个XML文件可能很有用。通常,每个单独的XML配置文件表示体系结构中的逻辑层或模块。
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
在前面的实例中,外部bean定义是从三个文件加载的服务。xml,messageSource。xml和themeSource.xml 所有位置路径都相对于执行导入的定义文件,因此services.xml必须与执行导入文件位置位于相同的目录或类路径位置,而messageSource.xml和themeSource.xml必须位于导入文件位置之下的资源位置。可以看到,前面的斜杠被忽略了。但是,考虑到这些路径是相对的,所以最好不要使用斜杠。根据Spring模式,要导入的文件的内容,包括顶级的<beans/>元素,必须是有效的XML bean定义。
它是可能的,但不推荐,在父目录中引用文件使用一个亲戚"../”路径。这样做会在当前应用程序之外的文件上创建一个依赖项。特别地,对于classpath: URLs(例如,classpath:.. ./services.xml),不推荐使用这个引用,因为运行时解析过程会选择“最近的”classpath根目录,然后查看它的父目录。类路径配置更改可能导致选择不同的、不正确的目录。
您总是可以使用完全限定的资源位置,而不是相对路径:例如,file:C:/config/services.xml或classpath:/config/services.xml。但是,请注意,您正在将应用程序的配置耦合到特定的绝对位置。通常更可取的做法是为这些绝对位置保留一个间接的地址——例如,通过“${…}”占位符,这些占位符在运行时根据JVM系统属性解析。 |
名称空间本身提供了import指令特性。除了普通bean定义之外,还有一些配置特性可以在Spring提供的XML名称空间选择中找到——例如,context
和util
名称空间。
Groovy Bean定义DSL
作为外部化配置元数据的另一个示例,bean定义也可以用Spring的Groovy bean定义DSL表示,这在Grails框架中是已知的。通常,这样的配置位于“。文件,其结构如下例所示:
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定义文件。
1.2.3 使用容器
ApplicationContext是能够维护不同bean及其依赖项的注册表的高级工厂接口。通过使用方法 T getBean(String ,<T> requiredType),你可以检索bean的实例。
ApplicationContext允许你读取bean定义并访问它们,如下面实例所示
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
对于Groovy配置,引导看起来非常类似。它有一个不同的上下文实现类,它支持groovy(但也理解XML bean定义)。下面的示例展示了Groovy配置:
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
最灵活的变体是GenericApplicationContext与reader委托相结合—例如,XmlBeanDefinitionReader用于XML文件,如下面的示例所示:
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();
您可以在相同的ApplicationContext上混合和匹配这样的reader委托,从不同的配置源读取bean定义。
然后可以使用getBean检索bean的实例。ApplicationContext接口有一些用于检索bean的其他方法,但在理想情况下,应用程序代码不应该使用它们。实际上,您的应用程序代码应该完全不调用getBean()方法,因此完全不依赖于Spring api。例如,Spring与web框架的集成为各种web框架组件(如控制器和jsf管理的bean)提供了依赖项注入,允许您通过元数据(如自动装配注释)声明对特定bean的依赖项
1.3 Bean的概述
SpringIoC容器管理一个或多个bean。这些bean是使用你提供给容器的配置元数据创建的(例如,以xml<bean/>定义的形式)。在容器内部,这些bean定义被表示伟BeanDefinition对象,其中包含(其他信息)以下元数据:
- 包限定的类名:通常是定义的bean的实现类。
- bean行为配置元素,它表示bean在容器中的行为(范围、生命周期回调等等).
- 对该bean执行其工作所需的其他bean的引用。这些引用也称为协作者或依赖项。
- 要在新创建的对象中设置的其他配置设置--例如,池的大小限制或在管理连接池的bean中使用的连接数。
此元数据转换为组成每个bean定义的一组属性。下表描述了这些属性:
Property(性质) | Explained in(阐述) |
Class | 实例化bean |
Name | 命名bean |
Scope | bean的范围 |
Constructor arguments | 依赖注入 |
Properties | 依赖注入 |
Autowiring mode | 自从装配 |
Lazy initialization mode | 延迟初始化bean |
Initialization method | 初始化回调 |
Destruction method | 销毁回调 |
除了包含关于如何创建特定bean的信息的bean定义之外,ApplicationContext实现还允许注册容器外创建的现有对象(由用户创建)。这是通过getBeanFactory()方法访问ApplicationContext的BeanFactory来实现的,该方法返回BeanFactory的DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(...)和registerBeanDefinition(...)方法支持这种注册。但是,典型的应用程序只使用通过常规定义元数据定义的bean。
Bean元数据和手动提供的单例实现需要尽早注册,已便于容器在自动装配和其他内省步骤期间正确地推断它们。虽然在某种程度上支持覆盖现有的元数据和现有的单例实例,但是在运行时这侧新bean(与对工厂的实时访问并发)并没有得到官方的支持,这可能会导致并发访问异常、bean容器中的不一致状态,或者两者都有 |
1.3.1 命名Bean