美文网首页
SpringFramework Core(一)

SpringFramework Core(一)

作者: 程序员文集 | 来源:发表于2019-12-20 21:44 被阅读0次

IoC容器

IoC也称为依赖注入(DI)。在此过程中,对象仅通过构造函数参数,工厂方法的参数或在构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即,与它们一起使用的其他对象) 。然后,容器在创建bean时注入那些依赖项。此过程从根本上讲是通过使用类的直接构造或诸如服务定位器模式的机制来控制其依赖关系的实例化或位置的Bean本身的逆过程(因此称为Control Inversion)。
org.springframework.beansorg.springframework.context包是Spring框架的IoC容器的基础。 BeanFactory 提供了一种高级配置机制,能够管理任何类型的对象。

ApplicationContextBeanFactory的子接口。它增加了:

  • 与Spring的AOP功能轻松集成

  • 消息资源处理(用于国际化)

  • 活动发布

  • 应用层特定的上下文,例如WebApplicationContext 用于Web应用程序中的。

在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。Bean是由Spring IoC容器实例化,组装和以其他方式管理的对象。否则,bean仅仅是应用程序中许多对象之一。Bean及其之间的依赖关系反映在容器使用的配置元数据中。

容器概述

org.springframework.context.ApplicationContext接口代表Spring IoC容器,并负责实例化,配置和组装Bean。容器通过读取配置元数据来获取有关要实例化,配置和组装哪些对象的指令。配置元数据以XML,Java批注或Java代码表示。它使您能够表达组成应用程序的对象以及这些对象之间的丰富相互依赖关系。

ApplicationContextSpring提供了该接口的几种实现。在独立应用程序中,通常创建ClassPathXmlApplicationContext 或的实例 FileSystemXmlApplicationContext。尽管XML是定义配置元数据的传统格式,但是您可以通过提供少量XML配置来声明性地启用对这些其他元数据格式的支持,从而指示容器将Java注释或代码用作元数据格式。

下图显示了Spring的工作原理的高级视图。您的应用程序类与配置元数据结合在一起,因此,在ApplicationContext创建和初始化后,您将拥有一个完全配置且可执行的系统或应用程序。


image

配置元数据

如上图所示,Spring IoC容器使用一种形式的配置元数据。这个配置元数据表示您作为应用程序开发人员如何告诉Spring容器实例化,配置和组装应用程序中的对象。

传统上,配置元数据以简单直观的XML格式提供,这是本章大部分内容用来传达Spring IoC容器的关键概念和功能的内容。

基于XML的元数据不是配置元数据的唯一允许形式。Spring IoC容器本身与实际写入此配置元数据的格式完全脱钩。如今,许多开发人员为他们的Spring应用程序选择 基于Java的配置

有关在Spring容器中使用其他形式的元数据的信息,请参见:

  • 基于注释的配置:Spring 2.5引入了对基于注释的配置元数据的支持。

  • 基于Java的配置:从Spring 3.0开始,Spring JavaConfig项目提供的许多功能成为核心Spring Framework的一部分。因此,您可以使用Java而不是XML文件来定义应用程序类外部的bean。要使用这些新功能,请参阅 @Configuration@Bean@Import,和@DependsOn注释。

基于XML的配置元数据将这些bean配置为<bean/>顶级元素内的<beans/>元素。Java配置通常@Bean在@Configuration类中使用带注释的方法。

这些bean定义对应于组成应用程序的实际对象。通常,您定义服务层对象,数据访问对象(DAO),表示对象(例如Struts Action实例),基础结构对象(例如Hibernate SessionFactories,JMS Queues等)。

以下示例显示了基于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的类型,并使用完全限定的类名。

实例化容器

提供给ApplicationContext构造函数的位置路径是资源字符串,这些资源字符串使容器可以从各种外部资源(例如本地文件系统,Java等)加载配置元数据CLASSPATH。

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

以下示例显示了服务层对象(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配置文件都代表体系结构中的逻辑层或模块。

可以使用应用程序上下文构造函数从所有这些XML片段中加载bean定义。Resource如上一节中所示,此构造函数具有多个位置 。或者,使用一个或多个出现的<import/>元素从另一个文件中加载bean定义。以下示例显示了如何执行此操作:

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

在前面的例子中,外部豆定义是从三个文件加载: services.xml,messageSource.xml,和themeSource.xml。所有位置路径是相对于定义文件做进口,因此services.xml必须在同一个目录或类路径位置作为文件做进口,而 messageSource.xml并themeSource.xml必须在resources进口文件的位置下方的位置。如您所见,斜杠被忽略。但是,鉴于这些路径是相对的,最好不要使用任何斜线。<beans/>根据Spring Schema,导入的文件的内容(包括顶层元素)必须是有效的XML bean定义。

使用容器

ApplicationContext是一个维护bean定义以及相互依赖的注册表的高级工厂的接口。通过使用方法T getBean(String name, Class<T> requiredType),您可以检索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();

后,您可以getBean用来检索bean的实例。该ApplicationContext 接口还有其他几种检索bean的方法,但是理想情况下,您的应用程序代码永远不要使用它们。实际上,您的应用程序代码应该根本不调用该 getBean()方法,因此完全不依赖于Spring API。例如,Spring与Web框架的集成为各种Web框架组件(例如控制器和JSF管理的Bean)提供了依赖项注入,使您可以通过元数据(例如自动装配注释)声明对特定Bean的依赖项。

Bean总览

Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的。

在容器本身内,这些bean定义表示为BeanDefinition 对象,其中包含(除其他信息外)以下元数据:

包限定的类名:通常,定义了Bean的实际实现类。

Bean行为配置元素,用于声明Bean在容器中的行为(作用域,生命周期回调等)。

对其他bean进行工作所需的引用。这些引用也称为协作者或依赖项。

要在新创建的对象中设置的其他配置设置,例如,池的大小限制或要在管理连接池的bean中使用的连接数。

Bean定义:

  • 类 Class
  • 名称 Name
  • scope 作用范围
  • 构造函数参数 Constructor arguments
  • 属性 Properties
  • 装配模式 Autowiring mode
  • 延迟初始化
  • 初始化方法
  • 销毁方法

除了包含有关如何创建特定bean的信息的bean定义之外,这些ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。这是通过ApplicationContext的getBeanFactory()来完成的,该方法返回BeanFactory。BeanFactory 通过registerSingleton(..)和 registerBeanDefinition(..)方法支持此注册。但是,典型的应用程序只能与通过常规bean定义元数据定义的bean一起使用。

Bean元数据和手动提供的单例实例需要尽早注册,以便容器在自动装配和其他自省步骤中正确地推理它们。尽管在某种程度上支持覆盖现有元数据和现有单例实例,但官方不支持在运行时(与对工厂的实时访问同时)对新bean的注册,并且可能导致并发访问异常,bean容器中的状态不一致。

Bean命名

每个bean具有一个或多个标识符。这些标识符在承载Bean的容器内必须是唯一的。一个bean通常只有一个标识符。但是,如果需要多个,则可以将多余的名字视为别名。

在基于XML配置文件,您可以使用id属性,该name属性,或两者来指定bean标识符。该id属性使您可以精确指定一个ID。按照惯例,这些名称是字母数字(“ myBean”,“ someService”等),但它们也可以包含特殊字符。如果要为bean引入其他别名,还可以在name 属性中指定它们,并用逗号(,),分号(;)或空格分隔。作为历史记录,在Spring 3.1之前的版本中,该id属性被定义为一种xsd:ID类型,该类型限制了可能的字符。从3.1开始,它被定义为xsd:string类型。请注意,Bean id唯一性仍由容器强制执行,尽管不再由XML解析器执行。

您不需要为bean 提供nameid。如果不提供 nameid显式提供,容器将为该bean生成一个唯一的名称。但是,如果要通过名称引用该bean,则通过使用ref元素或 服务定位器样式查找,必须提供一个名称。不提供名称的动机与使用内部bean自动装配合作者有关

Bean命名约定
约定是在命名bean时将标准Java约定用于实例字段名称。也就是说,bean名称以小写字母开头,并从那里用驼峰式大小写。这样的名字的例子包括accountManager, accountService,userDao,loginController,等等。

一致地命名Bean使您的​​配置更易于阅读和理解。另外,如果您使用Spring AOP,则在将建议应用于名称相关的一组bean时,它会很有帮助。

在Bean定义之外别名Bean

在bean定义本身中,可以通过使用id属性指定的最多一个名称和该属性中任意数量的其他名称的组合来为bean提供多个名称name。这些名称可以是同一bean的等效别名,并且在某些情况下很有用,例如通过使用特定于该组件本身的bean名称,让应用程序中的每个组件都引用一个公共依赖项。

但是,在实际定义bean的地方指定所有别名并不总是足够的。有时需要为在别处定义的bean引入别名。这在大型系统中通常是这种情况,在大型系统中,配置在每个子系统之间分配,每个子系统都有自己的对象定义集。在基于XML的配置元数据中,您可以使用<alias/>元素来完成此任务。以下示例显示了如何执行此操作:

<alias name="fromName" alias="toName"/>

在这种情况下,在使用该别名定义之后,命名为fromName 的Bean(位于同一容器中)的Bean也可以称为toName。

例如,子系统A的配置元数据可以通过名称引用数据源subsystemA-dataSource。子系统B的配置元数据可以使用的名称引用数据源subsystemB-dataSource。组成使用这两个子系统的主应用程序时,主应用程序使用名称引用数据源myApp-dataSource。要使所有三个名称都引用同一个对象,可以将以下别名定义添加到配置元数据中:

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

现在,每个组件和主应用程序都可以通过唯一的名称引用数据源,并保证不会与任何其他定义冲突(有效地创建名称空间),但它们引用的是同一bean。

实例化Bean

Bean定义本质上是创建一个或多个对象的方法。容器在被询问时会查看命名bean的配方,并使用该bean定义封装的配置元数据来创建(或获取)实际对象。

如果使用基于XML的配置元数据,则可以在<bean/>元素的class属性中指定要实例化的对象的类型(或类)。此 class属性(在内部是BeanDefinition 实例的Class属性)通常是必需的。

可以通过以下两种方式之一使用该Class属性:

通常,在容器本身通过反射性地调用其构造函数直接创建Bean的情况下,指定要构造的Bean类,这在某种程度上等同于使用new运算符的Java代码。

要指定包含要创建对象而调用的static工厂方法的实际类,在不太常见的情况下,容器将在类上调用 static工厂方法来创建Bean。从static工厂方法的调用返回的对象类型可以是同一类,也可以是完全不同的另一类。

用构造函数实例化

当通过构造方法创建一个bean时,所有普通类都可以被Spring使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定bean类就足够了。但是,根据您用于该特定bean的IoC的类型,您可能需要一个默认(空)构造函数。

Spring IoC容器几乎可以管理您要管理的任何类。它不仅限于管理真正的JavaBean。大多数Spring用户更喜欢仅具有默认(无参数)构造函数以及根据容器中的属性建模的适当的setter和getter的实际JavaBean。您还可以在容器中具有更多奇特的非bean样式类。例如,如果您需要使用绝对不符合JavaBean规范的旧式连接池,则Spring也可以对其进行管理。

使用基于XML的配置元数据,您可以如下指定bean类:

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

有关向构造函数提供参数(如果需要)并在构造对象之后设置对象实例属性的机制的详细信息,请参见 注入依赖项

用静态工厂方法实例化

在定义使用静态工厂方法创建的bean时,请使用class 属性来指定包含static工厂方法的类,并使用命名factory-method为属性的属性来指定工厂方法本身的名称。您应该能够调用此方法(带有可选参数,如后面所述),并返回一个活动对象,该对象随后将被视为已通过构造函数创建。这种bean定义的一种用法是static用旧版代码调用工厂。

以下bean定义指定通过调用工厂方法来创建bean。该定义不指定返回对象的类型(类),而仅指定包含工厂方法的类。在此示例中,该createInstance() 方法必须是静态方法。以下示例显示如何指定工厂方法:

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>

以下示例显示了可与前面的bean定义一起使用的类:

public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}

使用实例工厂方法实例化

使用实例工厂方法实例化从容器中调用现有bean的非静态方法以创建新bean。

要使用此机制,请将class属性保留为空,并在factory-bean属性中指定当前(或父容器或祖先容器)中包含要创建对象的实例方法的Bean的名称。使用factory-method属性设置工厂方法本身的名称。以下示例显示了如何配置此类Bean:

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

以下示例显示了相应的类:

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

这种方法表明,Factory Bean本身可以通过依赖项注入(DI)进行管理和配置。

相关文章

网友评论

      本文标题:SpringFramework Core(一)

      本文链接:https://www.haomeiwen.com/subject/hjtwnctx.html