Spring 框架核心(1)

本文档详细介绍了Spring框架的IoC容器和Bean,包括配置元数据、容器实例化、Bean定义及实例化。讲解了如何通过XML、GroovyDSL等方式配置Bean,以及使用构造函数、静态工厂和实例工厂方法实例化Bean。此外,还讨论了Bean的命名、别名以及依赖注入。
摘要由CSDN通过智能技术生成

版本 5.2.25.RELEASE

目录

1.IoC容器 

1.1.Spring框架的IoC容器和Beans简介

1.2容器概述 

1.2.1.配置元数据 

1.2.2.实例化容器 

编写基于XML的配置元数据 

GroovyBean定义DSL 

 1.2.3.使用容器

1.3.Bean概述 

1.3.1.命名beans

在Bean定义之外别名Bean 

 1.3.2.实例化Beans

使用构造函数实例化 

使用静态工厂方法进行实例化

使用实例工厂方法进行实例化 

确定Bean的运行时类型


该参考文档涵盖了Spring Framework所有核心技术:

  1. 最重要的是Spring框架的控制反转(IoC)容器
  2. 其次是Spring的面向方面编程(AOP)技术。Spring与AspectJ集成是目前  在功能方面最丰富最成熟的AOP实现。

1.IoC容器 

1.1.Spring框架的IoC容器和Beans简介

IoC也称为依赖注入(DI)。对象通过以下几种方式定义其依赖关系:

  1. 构造函数参数
  2. 工厂方法的参数
  3. 通过上述方式返回的对象实例上设置的属性

 容器在创建bean时注入这些依赖项。这个过程从根本上说是bean本身的反向(因此得名,反向控制)

Spring Framework IoC容器的基础包含:

  • org.springframework.bean包
  • org.springfframework.conf包

BeanFactory接口提供了一种高级配置机制,提供了配置框架和基本功能,能够管理任何类型的对象。ApplicationContext是BeanFactory的一个子接口,添加了更多特定于企业的功能,ApplicationContext是BeanFactory的一个完整超集: 

  • 更容易与Spring的AOP功能集成
  • 消息资源处理(用于国际化)
  • 事件发布
  • 应用层特定的上下文,例如用于web应用程序的WebApplicationContext。

bean的定义:在Spring中,构成应用程序主干并由Spring IoC容器管理的对象,它是由Spring IoC容器实例化、组装和管理的对象。Bean之间的依赖关系反映在容器使用的配置元数据中。 

1.2容器概述 

org.springframework.context.ApplicationContext接口:

  1. 表示Spring IoC容器。
  2. 负责实例化、配置和组装bean。
  3. 通过读取配置元数据(配置元数据用XML、Java注释或Java代码表示)来获取关于实例化、配置和组装哪些对象的指令。

Spring提供了ApplicationContext接口的几个实现,如在独立应用程序中包含:

  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext

下图显示了Spring工作的视图:

1.2.1.配置元数据 

如上图所示,Spring IoC容器使用一种形式的配置元数据。配置元数据的方式包含:

  1. 传统上,配置元数据是以简单直观的XML格式提供的
  2. Spring 2.5引入了对基于注解配置元数据的支持
  3. 基于Java的配置:从Spring 3.0开始,Spring JavaConfig项目提供的许多功能成为核心Spring框架的一部分。

Spring配置由容器必须管理的至少一个(通常不止一个)bean定义组成。

  • 基于XML的配置元数据的顶层为<beans/>元素中的<beans>元素
  • Java配置通常在@configuration类中使用@Bean注释的方法

以下示例显示了基于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="...">  
        <!-- 这个bean的合作者和配置转到这里 -->
    </bean>

    <bean id="..." class="...">
        <!-- 这个bean的合作者和配置转到这里 -->
    </bean>

    <!-- 这里有更多bean定义 -->

</beans>

配置中的Bean属性说明:

  • id属性是一个字符串,用于标识单个bean定义
  • class属性定义bean的类型,并使用完全限定的类名。

1.2.2.实例化容器 

提供给ApplicationContext构造函数的一个或多个位置路径是允许容器从各种外部资源(如本地文件系统、Java CLASSPATH等)加载配置元数据的资源文件。

Java

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

Kotlin

val context = 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">

    <!-- 服务 -->

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        <!-- 此bean的其他合作者和配置请访问此处 -->
    </bean>

    <!-- 有关服务的更多bean定义,请访问此处 -->

</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">
        <!-- 此bean的其他合作者和配置请访问此处 -->
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
        <!-- 此bean的其他合作者和配置请访问此处-->
    </bean>

    <!--数据访问对象的bean定义越来越多 -->

</beans>

说明:在前面的示例中,服务层由PetStoreServiceImpl类和两个类型为JpaAccountDao和JpaItemDao的数据访问对象组成(基于JPA对象关系映射标准)。property name元素是指JavaBean属性的名称,ref元素是指另一个bean定义的名称。id和ref元素之间的这种链接表达了协作对象之间的依赖关系。

编写基于XML的配置元数据 

bean定义跨越多个XML文件说明:

  1. 可以使用应用程序上下文构造函数从所有这些XML片段加载bean定义。
  2. 使用一个或多个<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>

在前面的例子中,外部bean定义是从三个文件加载的:services.xml、messageSource.xml和themeSource.xml。因采用相对路径进行文件导入,它们的路径需满足以下条件:

  1. services.xml与进行导入的文件位于同一目录或类路径位置
  2. messageSource.xml和themeSource.xml须位于导入文件位置下方的资源位置(如您所见,前导斜杠被忽略,所以最好不要使用斜线)。

可以(但不建议)使用相对“../”路径引用父目录中的文件。推荐使用完全限定的资源位置:例如,file:C:/config/services.xml或classpath:/config/services..xml。对于这样的绝对位置,通常优选保持间接性 — 例如,通过“${…​}“在运行时根据JVM系统属性解析的占位符。

GroovyBean定义DSL 

bean定义也可以在Spring的GroovyBean Definition DSL中表达,这样的配置存在于“.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
        }
    }
}

这种配置风格在很大程度上等同于XMLbean定义,甚至支持Spring的XML配置名称空间。它还允许通过importBeans指令导入XMLbean定义文件

 1.2.3.使用容器

ApplicationContext是高级工厂的接口,能够维护不同bean及其依赖项的注册。通过使用方法T getBean(String name,Class<T>requiredType),可以检索bean的实例。

ApplicationContext允许您读取bean定义并访问它们,如下例所示: 

Java

// 创建和配置bean
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// 检索已配置的实例
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// 使用配置的实例
List<String> userList = service.getUsernameList();

Kotlin

import org.springframework.beans.factory.getBean

//创建和配置bean
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")

// 检索已配置的实例
val service = context.getBean<PetStoreService>("petStore")

// 使用配置的实例
var userList = service.getUsernameList()

以下示例显示Groovy配置:

Java

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");

Kotlin

val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")

最灵活的变体是GenericApplicationContext与读者委托相结合 — 例如,使用XML文件的XmlBeanDefinitionReader,如下例所示:

Java

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

Kotlin

val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()

您还可以将GroovyBeanDefinitionReader用于Groovy文件,如下例所示:

Java

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();

Kotlin

val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
context.refresh()

您可以在同一ApplicationContext上混合和匹配这样的读取器委托,从不同的配置源读取bean定义。

然后可以使用getBean来检索bean的实例。

ApplicationContext接口还有一些其他方法用于检索bean,但理想情况下,应用程序代码不应该使用它们。实际上,您的应用程序代码根本不应该调用getBean()方法,因此根本不依赖于SpringAPI。例如,Spring与web框架的集成为各种web框架组件(如控制器和JSF管理的bean)提供了依赖注入,允许您通过元数据(如自动装配注解)声明对特定bean的依赖。

1.3.Bean概述 

Spring IoC容器管理一个或多个bean。其中Bean包含(除其他信息外)以下元数据: 

  • 包限定的类名:通常是要定义的bean的实际实现类。
  • Bean行为配置元素,说明Bean在容器中的行为(作用域、生命周期回调等)。
  • 对bean执行其工作所需的其他bean的引用。这些引用也称为合作者或依赖关系。
  • 要在新创建的对象中设置的其他配置设置 — 例如,池的大小限制或在管理连接池的bean中使用的连接数。

下表介绍了Bean属性: 

属性在以下章节解析

Class

实例化Bean

Name

命名Bean

Scope

bean的作用域

Constructor arguments

依赖项注入

Properties

依赖项注入

Autowiring mode

自动装配器

Lazy initialization mode

懒初始化bean

Initialization method

初始化回调

Destruction method

销毁回调

除配置元数据方法定义bean之外,ApplicationContext实现还允许由用户注册并在容器外部创建的现有对象。

  1. 通过getBeanFactory()方法访问ApplicationContext的BeanFactory返回BeanFactory DefaultListableBeanFactory
  2. DefaultListableBeanFactory通过registerSingleton(..)和registerBeanDefinition(..)方法支持此注册。

Bean元数据和手动提供的singleton实例需要尽早注册,以便容器在自动装配和其他内部步骤期间正确地配置它们。官方不支持在运行时注册新的bean(与对工厂的实时访问同时进行),这可能会导致并发访问异常、bean容器中的状态不一致,或两者兼而有之。 

1.3.1.命名beans

bean标识符说明:

  1. 在基于XML的配置元数据中使用id属性、name属性或两者来指定bean标识符。id属性只允许指定一个id,可以通过设置name属性指定bean的多个别名(用,、;或空格分隔)
  2. 在Spring3.1之前的版本中,id属性被定义为xsd:id类型,它约束了可能的字符。
  3. 从3.1开始,它被定义为xsd:string类型。bean id的唯一性由容器强制执行
  4. 如果没有显式提供名称或id,容器将为该bean生成一个唯一的名称。
  5. 如果想通过使用ref元素或ServiceLocator样式的查找来按名称引用该bean,则必须提供一个名称。
  6. 不提供名称则使用内部bean和自动装配器完成依赖注入。 
  7. bean名称以小写字母开头,并从此处开始使用驼色大小写。

通过类路径中的组件扫描,Spring为未命名的组件生成bean名称,遵循前面描述的规则:本质上,采用简单的类名并将其初始字符改为小写。然而,在(不寻常的)特殊情况下,当有多个字符,并且第一个和第二个字符都是大写时,原始大小写会被保留。这些规则与java.beans.Interspector.decapital(Spring在这里使用)定义的规则相同。 

在Bean定义之外别名Bean 

在基于XML的配置元数据中,可以使用<alias/>元素来实现Bean的别名。以下示例显示了如何执行此操作: 

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

例如,

  1. 子系统A的配置元数据可以通过子系统A DataSource的名称引用DataSource。
  2. 子系统B的配置元数据可以通过子系统B DataSource的名称引用DataSource。
  3. 在编写同时使用这两个子系统的主应用程序时,主应用程序通过myApp DataSource的名称引用DataSource。

要使所有三个名称都引用同一对象,可以将以下别名定义添加到配置元数据中:

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

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

Java配置如果您使用Javaconfiguration,@Bean注释可以用于提供别名。有关详细信息,请参阅使用@Bean注释。

 1.3.2.实例化Beans

使用基于XML的配置元数据,则在<bean/>元素的class属性中指定要实例化的对象的类型(或类)。通过以下两种方式之一使用Class属性:

  • 通常,在容器本身通过反射调用其构造函数直接创建Bean的情况下,指定要构造的Bean类。
  • 指定包含静态工厂方法的实际类,该方法被调用来创建对象,在不太常见的情况下,容器调用类上的静态工厂方法来创建bean。调用静态工厂方法返回的对象类型可能是同一个类,也可能完全是另一个类。 

嵌套类名

为嵌套类配置bean定义使用嵌套类的二进制名称或源名称。
如com.example包中有一个名为SomeThing的类,而这个SomeThig类有一个称为Otherhing的静态嵌套类,它们可以用 $ 或 . 分隔。class属性是com.example.SomeThing$Otherhing或com.example.SemeThing.Otherhing。 

使用构造函数实例化 

必要条件:类需要一个默认(空)构造函数。

基于XML配置,如下所示:

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

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

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

使用静态工厂方法进行实例化

必要条件:class属性指定包含静态工厂方法的类,并使用名为factory- method的属性指定工厂方法本身的名称。
基于XML配置,如下所示:

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

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

Java

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

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

Kotlin

class ClientService private constructor() {
    companion object {
        private val clientService = ClientService()
        fun createInstance() = clientService
    }
}

有关向工厂方法提供(可选)参数以及在从工厂返回对象后设置对象实例属性的机制的详细信息,请参阅详细信息中的依赖项和配置。

使用实例工厂方法进行实例化 

​实例工厂方法:从容器中调用现有bean的非静态方法来创建新bean。

必要条件:

  1. class属性保留为空
  2. 在factory-bean属性中指定工厂名称。
  3. 使用factory-method属性设置工厂方法本身的名称

 以下示例显示了如何配置这样一个bean:​

<!-- 工厂bean,它包含一个名为createInstance()的方法 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- 要通过工厂bean创建的bean -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

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

Java

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

Kotlin

class DefaultServiceLocator {
    companion object {
        private val clientService = ClientServiceImpl()
    }
    fun createClientServiceInstance(): ClientService {
        return clientService
    }
}

一个工厂类也可以包含多个工厂方法,如下例所示:

<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- 注入该定位器bean所需的任何依赖项 -->
</bean>

<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

<bean id="accountService"
    factory-bean="serviceLocator"
    factory-method="createAccountServiceInstance"/>

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

Java

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    private static AccountService accountService = new AccountServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }

    public AccountService createAccountServiceInstance() {
        return accountService;
    }
}

Kotlin

class DefaultServiceLocator {
    companion object {
        private val clientService = ClientServiceImpl()
        private val accountService = AccountServiceImpl()
    }

    fun createClientServiceInstance(): ClientService {
        return clientService
    }

    fun createAccountServiceInstance(): AccountService {
        return accountService
    }
}

这种方法表明,工厂bean本身可以通过依赖注入(DI)进行管理和配置。请参阅“依赖项和配置”的详细信息。

确定Bean的运行时类型

特定bean的运行时类型是很难确定的。了解特定bean的实际运行时类型的推荐方法是对指定bean名称进行BeanFactory.getType调用。这将考虑以上所有情况,并返回BeanFactory.getBean调用将为相同的bean名称返回的对象类型。 

bean元数据定义中的指定类只是一个初始类引用,可能与声明的工厂方法组合,或者是FactoryBean类,这可能会导致bean的运行时类型不同,或者在实例级工厂方法的情况下根本没有设置(而是通过指定的工厂bean名称解析)。此外,AOP代理可以使用基于接口的代理来包装bean实例,该代理对目标bean的实际类型(仅其实现的接口)具有有限的公开。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2301_79678418

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值