栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring文档

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring文档

Spring Framework:https://spring.io/projects/spring-framework

本次阅读Spring 5.3.21:https://docs.spring.io/spring-framework/docs/current/reference/html/

由官网目录可知,大致可分为八个章节进行阅读:

当前阅读进度:Core篇

Core Technologies

名词说明:

Inversion of Control (Ioc)

Aspect-Oriented Programming (AOP)

dependency injection(DI)

bean

dependency

configuration metadata

在Spring文档中,“factory bean”指的是在Spring容器中配置的bean,它通过实例或静态工厂方法创建对象。相比之下,FactoryBean(注意大写)指的是spring特定的FactoryBean实现类。

Spring框架有自己的AOP框架,它在概念上很容易理解,并且成功地解决了Java企业编程中AOP需求的80%的最佳点。

Spring集成了AspectJ。

1. The IoC Container 1.1. Introduction to the Spring IoC Container and Beans

IoC也被称为依赖注入(DI)。

IoC是一个过程,对象仅通过构造函数参数、工厂方法的参数或在对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义它们的依赖关系。

org.springframework.beans和org.springframework.context包是Spring框架IoC容器的基础。

BeanFactory接口提供了一种高级的配置机制,能够管理任何类型的对象。

ApplicationContext是BeanFactory的子接口。它具有:

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

ApplicationContext是BeanFactory的一个完整超集。

受Spring IoC容器管理的对象称为bean。

bean是由Spring IoC容器实例化、组装和管理的对象。

bean及其之间的依赖关系反映在容器使用的配置元数据中。

1.2. Container Overview

org.springframework.context.ApplicationContext接口代表着Spring IoC容器,并负责实例化、配置和组装bean。

容器通过读取配置元数据来获取关于实例化、配置和组装哪些对象的指令。

配置元数据用XML、Java注释或Java代码表示。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。

Spring提供了ApplicationContext接口的几个实现。在单体应用程序中,通常会创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。

1.2.1. Configuration Metadata

配置元数据是作为一个开发者与container沟通的桥梁。

基于xml的配置元数据将这些bean配置为顶级元素中的元素。Java配置通常在@Configuration类中使用@bean注释的方法。

这些bean定义对应于构成应用程序的实际对象。通常在定义Service layer对象、data access objects (DAOs)、表示对象(如Struts Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues等等。通常,不需要在容器中配置细粒度的domain对象,因为创建和加载domain对象通常是dao和业务逻辑的职责。

最基础的XML配置:

id属性是标识各个bean定义的字符串。(id属性可以用作被其他对象引用的唯一标识)

class属性定义bean的类型,需要使用类的完全限定名。




      
        
    

    
        
    

    


1.2.2. Instantiating a Container

提供给ApplicationContext构造器的 location path或paths是resource 字符串,容器可以从各种外部资源加载配置元数据,例如local file system、Java CLASSPATH等。

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
//位于resource目录下的services.xml



    

    
        
        
        
    

    


//位于resource目录下的daos.xml



    
        
    

    
        
    

    


Composing XML-based Configuration Metadata

通常,每个单独的XML配置文件代表体系结构中的一个逻辑层或模块。可以使用一次或多次元素从另一个或多个文件加载bean定义。


    //当前目录
    
    //resources目录下找
    
    //忽略最前面的斜杠
    

    
    

namespace本身提供了导入指令特性。除了普通bean定义之外,Spring提供的一系列XML名称空间还提供了更多的配置特性—例如,context和util。

The Groovy Bean Definition DSL

略

1.2.3. Using the Container

ApplicationContext是高级工厂的接口,该工厂能够维护不同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 userList = service.getUsernameList();

最灵活的变体是GenericApplicationContext与Reader委托的组合——例如,XML文件的XmlBeanDefinitionReader,如下所示:

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

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

在容器本身内部,这些bean definitions 被表示为BeanDefinition对象,它包含且不仅限于以下元数据:

  • 类的全限定名:通常是需要定义的bean的实际实现类。
  • Bean行为配置元素,Bean在容器中需要执行特定的动作(范围、生命周期回调等等)。
  • 对bean执行所需的其他bean的引用。这些引用也称为协作者或依赖项。
  • 要对第三方配置类通过在新创建的对象中设置成符合适合自己项目的bean—例如,池的大小限制或在管理连接池的bean中使用的连接数。

bean definitions内的属性

详情可参见:org.springframework.beans.factory.config.BeanDefinition

PropertyExplained in…
ClassInstantiating Beans
NameNaming Beans
ScopeBean Scopes
Constructor argumentsDependency Injection
PropertiesDependency Injection
Autowiring modeAutowiring Collaborators
Lazy initialization modeLazy-initialized Beans
Initialization methodInitialization Callbacks
Destruction methodDestruction Callbacks

除了包含如何创建特定bean的信息的bean definitions 之外,ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。它是通过getBeanFactory()方法访问ApplicationContext的BeanFactory来完成的,该方法返回DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(…)和registerBeanDefinition(…)方法支持这种注册。但是,通常应用程序都只使用常规bean definitions元数据定义的bean,像这种由用户创建的情况较为少见,且官方并不推荐这种方式。【暂时没有从源码中验证这一段】

1.3.1. Naming Beans

每个bean可以有一个或多个标识符。这些标识符在bean的当前容器中必须是唯一的。一个bean一般只有一个标识符,如果它需要一个以上的标识符,则额外的可以被认为是别名。

在基于xml的配置元数据中,可以使用id属性、name属性或两者来指定bean标识符。id属性允许您指定一个id。按照惯例,这些名称是字母数字(‘myBean’, ’ someeService '等,按Java程序员的习惯一般都是小驼峰命名,这是官方推荐的写法)【一般情况组件会取简单类名并将第一个字符从大写转换为小写,但是在特殊情况下,即当有多个字符并且第一个和第二个字符都是大写字符时,将保留原来的大小写。全是小写也一样。】,但它们也可以包含特殊字符。如果希望引入bean的其他别名,还可以在name属性中指定它们,用逗号(,)、分号(;)或空格分隔【进一步证明name属性可以有多个,而且是唯一的标识符】。

如果您没有为bean提供name或id,容器会自动为该bean生成一个唯一的name。但是,如果想通过name引用该bean,则需要使用ref element 或Service Locator style 查找,则必须提供name。不提供name的原因与 inner beans 的使用和 autowiring collaborators有关。

Aliasing a Bean outside the Bean Definition

指定bean实际定义的所有别名并不总是足够的,有时需要为在其他地方定义的bean引入别名。这种情况在大型系统中很常见,配置被划分到每个子系统中,每个子系统有自己的一组对象定义。在基于xml的配置元数据中,可以使用元素来完成此任务。下面的例子展示了如何这样做:


在该案例中,在使用别名定义之后,名为fromName的bean在同一个容器中可以被称为toName。

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



现在,每个组件和主应用程序都可以通过一个唯一的名称引用dataSource,该名称保证不会与任何其他定义(实际上创建了一个名称空间)冲突,但它们引用的是同一个bean。【当然也可以使用Java注解配置@Bean中的别名进行定义】

1.3.2. Instantiating Beans

原文引用:

A bean definition is essentially a recipe for creating one or more objects. The container looks at the recipe for a named bean when asked and uses the configuration metadata encapsulated by that bean definition to create (or acquire) an actual object.

bean定义本质上是创建一个或多个对象的方法。容器在被请求时查看指定bean的配方,并使用该bean定义封装的配置元数据来创建(或获取)实际对象。【我觉得recipe翻译成模板可能更合理一点】

如果使用xml的配置元数据,则需要在元素的class属性中指定要实例化的对象的类型(或类)。这个类属性(在内部是BeanDefinition实例上的class属性)通常是强制性的。使用Class属性有两种方式:

  • 通常,在容器本身通过反射机制调用其构造函数来直接创建bean的情况下,指定要构造的bean类,这在某种程度上相当于使用new操作符的Java代码。
  • 要指定包含用于创建对象的静态工厂方法的实际类,在较不常见的情况下,容器调用类上的静态工厂方法来创建bean。调用静态工厂方法返回的对象类型可以是同一个类,也可以完全是另一个类。

如果您希望为内部类配置bean定义,您可以使用内部类的二进制名称或源名称。

例如,如果您在 com.example 包下有一个名为SomeThing的类。这个SomeThing类有一个静态内部类OtherThing,它们可以用一个美元符号( ) 或一个点 ( . ) 分隔。因此, b e a n 定义中的 c l a s s 属性值可以是 ‘ c o m . e x a m p l e . S o m e T h i n g )或一个点(.)分隔。因此,bean定义中的class属性值可以是 `com.example.SomeThing )或一个点(.)分隔。因此,bean定义中的class属性值可以是‘com.example.SomeThingOtherThing 或者com.example.SomeThing.OtherThing`。

Instantiation with a Constructor

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

Spring IoC容器实际上可以管理您希望它管理的任何类。它并不仅限于管理真正的JavaBean。大多数Spring用户更喜欢实际的JavaBean(只有一个默认(无参数)构造函数,并根据容器中的属性创建相应的setter和getter)。

使用xml的配置元数据,您可以如下所示指定bean类:




此处为使用类的默认空构造器创建对应的bean,当然也可以通过有参构造器注入相应的依赖。

Instantiation with a Static Factory Method

在定义使用静态工厂方法创建的bean时,使用class属性来指定包含静态工厂方法的类,并使用factory-method属性来指定静态工厂方法名。这种实例化方式也会被当成构造注入,没有携带参数默认是无参构造。

下面的bean定义指定该bean将通过调用工厂方法来创建。定义没有指定返回对象的类型(类),而是指定包含工厂方法的类。在这个例子中,createInstance()方法必须是一个静态方法。下面的例子展示了如何指定一个工厂方法:

//静态工厂方法名
public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

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

该实例化方式同样可以有参构造注入。

Instantiation by Using an Instance Factory Method

与通过静态工厂方法进行的实例化类似,使用实例工厂方法进行的实例化从容器中调用现有bean的非静态方法来创建新bean。要使用此机制,需要将class属性保留为空,并在factory-bean属性中指定包含用于创建对象的实例方法的当前(或父或祖先)容器中的bean名称。使用factory-method属性设置工厂方法本身的名称。下面的例子展示了如何配置这样一个bean:



    




public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

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


    





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;
    }
}

这种方法表明工厂bean本身可以通过依赖注入(DI)进行管理和配置。

Determining a Bean’s Runtime Type

特定bean的运行时类型的确定并不简单。bean metadata definition中的指定类只是一个初始类引用,可能与声明的工厂方法结合在一起,或者是可能导致bean的不同运行时类型的FactoryBean类,或者在实例级工厂方法(而是通过指定的工厂bean名称解析)的情况下根本不设置。此外,AOP代理可以用基于接口的代理包装一个bean实例,该代理有限地公开目标bean的实际类型(只公开其实现的接口)。

原文引用:

The recommended way to find out about the actual runtime type of a particular bean is a BeanFactory.getType call for the specified bean name. This takes all of the above cases into account and returns the type of object that a BeanFactory.getBean call is going to return for the same bean name.

推荐找到实际运行时类型的方式是通过BeanFactory.getType调用具体的Bean名。这将考虑上述所有情况,并返回BeanFactory的对象类型。getBean调用将返回相同的bean名称。【翻译的很奇怪,后面想起来的再回来修改。】

插一句:这是读文档的第二天,这是我读这篇Spring文档的第二遍了,是真的感觉到很枯燥很难熬。但是我还想再坚持几天看看结果到底怎样。

1.4. Dependencies

通常的企业应用程序不可能仅由单个对象(bean)组成的。即使是最简单的应用程序也有几个对象一起工作,以呈现最终用户眼中的一致应用程序。下一节将解释如何从定义许多独立的bean定义到完全实现的应用程序(其中对象协作以实现目标)。

1.4.1. Dependency Injection

IoC是一个过程,对象仅通过构造函数参数、工厂方法的参数或在对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义它们的依赖关系。

当对象与它们的依赖项一起提供时使用依赖注入原则可以使得代码更加整洁,解耦会更有效。对象不需要查找其依赖项,也不需要知道依赖项的位置或类。因此,您的类变得更容易测试,特别是当依赖关系在接口或抽象基类上时,这允许在单元测试中使用存根或模拟实现。

DI主要有两种形式:构造函数的依赖注入和setter的依赖注入。

Constructor-based Dependency Injection

基于构造函数的DI是由容器调用带有许多参数的构造函数来完成的,每个参数代表一个依赖项。调用带有特定参数的静态工厂方法来构造bean与其几乎是等价的,本文将以类似的方式处理构造函数和静态工厂方法的参数。下面的例子展示了一个只能通过构造函数注入来进行依赖注入的类:

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on a MovieFinder
    private final MovieFinder movieFinder;

    // a constructor so that the Spring container can inject a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...
}

Constructor Argument Resolution

构造函数参数解析匹配在使用参数的类型是发生。如果bean定义的构造函数参数中不存在潜在的歧义,那么在bean definition中定义构造函数参数的顺序就是在实例化bean时将这些参数提供给适当的构造函数的顺序。考虑下面的类:

package x.y;

public class ThingOne {

    public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
        // ...
    }
}

假设ThingTwo和ThingThree类通过继承不相关,那么就不存在潜在的歧义。因此,下面的配置工作得很好,并且您不需要在元素中显式地指定构造函数参数索引或类型。


    
        
        
    

    

    

当引用另一个bean时,类型是已知的,可以进行匹配(如上例所示)。当使用简单类型时,例如true, Spring无法确定值的类型,因此无法在没有帮助的情况下通过类型进行匹配。考虑下面的类:

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private final int years;

    // The Answer to Life, the Universe, and Everything
    private final String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}

Constructor argument type matching

在上述场景中,如果使用type属性显式指定构造函数实参的类型,容器可以使用简单类型匹配的类型,如下所示:


    
    

Constructor argument index

你可以使用index属性来显式指定构造函数参数的索引,如下面的例子所示:


    
    

除了解决多个简单值的不确定性外,指定索引还可以解决构造函数具有两个相同类型参数时的不确定性。【索引从0开始】

Constructor argument name

您还可以使用构造函数参数名来消除值歧义,如下示例所示:


    
    

请记住,要使此功能开箱即用,必须在编译代码时启用调试标志,以便Spring可以从构造函数中查找参数名称。如果你不能或不想使用调试标志来编译代码,也可以使用@ConstructorProperties JDK注解显式地命名构造函数参数。然后,示例类必须如下所示:

package examples;

public class ExampleBean {

    // Fields omitted

    @ConstructorProperties({"years", "ultimateAnswer"})
    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}
Setter-based Dependency Injection

基于setter的DI是由容器在调用无参数构造函数或无参数静态工厂方法来实例化bean之后调用bean中的setter方法来完成的。

下面的例子展示了一个只能通过使用纯setter注入来进行依赖注入的类。这个类是Java传统的不依赖于容器特定接口、基类或注解的POJO。

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...
}

ApplicationContext为其管理的bean支持基于构造函数和基于setter的DI。它还支持在已经通过构造函数方法注入了一些依赖项之后,继续基于setter的DI。您以BeanDefinition的形式配置依赖项,您可以将其与PropertyEditor实例一起使用,以将属性从一种格式转换为另一种格式。然而,大多数Spring用户并不直接(即通过编程方式)使用这些类,而是使用XML bean定义、带注解的组件(即使用@Component、@Controller等注解的类)或基于java的@Configuration类中的@Bean方法。然后将这些源在内部转换为BeanDefinition的实例,并用于加载整个Spring IoC容器实例。

Dependency Resolution Process

容器执行bean依赖解析流程如下:

  • 创建和初始化ApplicationContext的同时记录所有bean的配置元数据。配置元数据可以是XML、Java代码或注解形式的。

  • 对于每个bean,其依赖关系以属性、构造函数参数或静态工厂方法参数的形式表示(如果使用静态工厂方法而不是普通构造函数)。这些依赖项是在实际创建bean时提供给bean的。

  • 每个属性或构造函数参数都是要设置的值的实际定义,或者是对容器中另一个bean的引用。

  • 每个属性或构造函数参数都从指定格式转换为该属性或构造函数参数的实际类型的值。默认情况下,Spring可以将字符串格式提供的值转换为所有内置类型,例如 int, long, String, boolean 等。

Spring容器在创建容器时就会验证每个bean的配置。但是,只有在实际创建该bean实例时才会设置bean属性。 singleton-scoped 并设置为**预实例化(默认)**的bean是在创建容器时创建的,否则只有在请求bean时才创建它。创建一个bean可能会由于创建和分配了bean的依赖及其依赖的依赖导致创建出一个bean图。请注意,这些依赖项之间的解析不匹配可能会在较晚的时候出现,即在第一次创建受影响的bean时。

Circular dependencies【循环依赖,有空回来再写】

您通常可以相信Spring会做正确的事情。它在容器加载时检测配置问题,例如对不存在的bean的引用和循环依赖项。Spring在bean实际创建时设置属性并解析依赖项。这意味着,正确加载的Spring容器可以在稍后请求对象时生成异常,如果创建该对象或其依赖项存在问题,例如,bean由于缺少或无效属性而抛出异常。某些配置问题的可见性可能会延迟,这就是ApplicationContext实现默认预实例化单例bean的原因。在实际需要这些bean之前创建这些bean需要花费一些前期时间和内存,您会在创建ApplicationContext时发现配置问题,而不是稍后。您仍然可以重写此默认行为,以便单例bean延迟初始化,而不是提前实例化。

如果不存在循环依赖项,那么当一个或多个协作bean被注入到依赖bean中时,每个协作bean在注入到依赖bean之前都要完全配置。这意味着,如果bean A对bean B有依赖,Spring IoC容器在调用bean A上的setter方法之前完全配置了bean B。换句话说,bean被实例化(如果它不是预实例化的单例)时,它的依赖项就被设置了,并且相关的生命周期方法(例如配置的init方法或InitializingBean回调方法)也会被调用。

Examples of Dependency Injection

下面的示例使用基于xml的配置元数据进行基于setter的DI。Spring XML配置文件的一小部分指定了一些bean定义如下:


    
    
        
    

    
    
    




public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }
}

在前面的示例中,声明了与XML文件中指定的属性匹配的setter。下面的例子使用了基于构造函数的DI:


    
    
        
    

    
    

    




public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public ExampleBean(
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.i = i;
    }
}

现在考虑这个例子的一个变体,其中,Spring被告知调用一个静态工厂方法来返回对象的一个实例,而不是使用构造函数:


    
    
    




public class ExampleBean {

    // a private constructor
    private ExampleBean(...) {
        ...
    }

    // a static factory method; the arguments to this method can be
    // considered the dependencies of the bean that is returned,
    // regardless of how those arguments are actually used.
    public static ExampleBean createInstance (
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {

        ExampleBean eb = new ExampleBean (...);
        // some other operations...
        return eb;
    }
}

静态工厂方法的参数由元素提供,与实际使用的构造函数完全相同。工厂方法返回的类的类型不必与包含静态工厂方法的类的类型相同(尽管在本例中是相同的)。也可以使用实例工厂方法完成相应的操作,本处不再讨论这些。

1.4.2. Dependencies and Configuration in Detail

如上一节所述,您可以将bean属性和构造函数参数定义为对其他bean的引用或内置类型的值。为此,Spring基于xml的配置元数据在其和元素中支持子元素类型。

Straight Values (Primitives, Strings, and so on)

标签的value属性可以将属性或构造函数参数通过字符串表示。Spring的转换服务可以将这些值从String转换为属性或参数的实际类型。下面的例子显示了正在设置的各种值:


    
    
    
    
    

下面的示例可以使用p-namespace进行更简洁的XML配置:



    


你也可以配置 java.util.Properties 实例,如下所示:



    
    
        
            jdbc.driver.className=com.mysql.jdbc.Driver
            jdbc.url=jdbc:mysql://localhost:3306/mydb
        
    

Spring容器通过使用JavaBeans的 PropertyEditor机制将元素中的文本转换为java.util.Properties实例。这是一个很好的快捷方式,也是Spring团队喜欢使用嵌套的元素而不是值属性样式的少数几个地方之一。

The idref element

idref元素只是将容器中另一个bean的id(与value对比:仅仅是字符串,而不是引用)传递给或元素的一种防错方法。下面的例子展示了如何使用它:




    
        
    

等价片段:




    

第一种形式比第二种形式更可取,因为使用idref标签可以让容器在部署时验证被引用的命名bean是否确实存在。在第二个片段中,没有对传递给客户端bean的targetName属性的值执行验证。只有在实际实例化客户端bean时才会发现检测出错误(极有可能导致致命的结果)。如果客户端bean是一个 prototype bean,那么这个错误和产生的异常只有在容器部署很久之后才会被发现。

【idref标签中的local属性不要再用了,由bean属性替换了】

标签所携带的值(至少在Spring 2.0之前的版本中)是在ProxyFactoryBean bean definition中的AOP拦截器的配置中。在指定拦截器名称时使用元素可以防止将拦截器ID拼错。

References to Other Beans (Collaborators)

ref标签是或定义标签中的最后一个标签。在这个标签中,您可以将一个bean的指定属性的值设置为同样受容器管理的另一个bean的引用。被引用的bean将会被设置成bean的属性,即作为该bean一个依赖项,并且在设置成属性之前需要对其进行初始化【如果没有在这之前没有被初始化的话】。所有的引用最终都是对另一个对象的引用。Scoping 和 validation 取决于您是否通过 bean 属性或 parent 属性指定其他对象的ID或name。

通过标签的bean属性指定目标bean是最通用的形式,它允许在同一容器或父容器中创建对任何bean的引用,而不管它是否在同一个XML文件中。bean属性的值可能与目标bean的id属性相同,或者与目标bean的name属性中的某个值相同。下面的例子展示了如何使用ref元素:


通过parent属性指定目标bean将创建对当前容器父容器中的bean的引用。父属性的值可能与目标bean的id属性或目标bean的name属性中的一个值相同。目标bean必须位于当前bean的父容器中。当您拥有容器的层次结构,并且您希望使用与父bean同名的代理将现有的bean包装在父容器中时,您应该主要使用此bean引用变体。下面的两个片段展示了如何使用parent属性:



    



    >
    
         
    
    

Inner Beans

可以一个在标签中的或标签的内部使用标签定义一个内部bean,如下所示:


    
    
         
            
            
        
    

内部bean定义的时候不需要指定的id和name属性,容器会忽略内部bean的这些标识符。容器在创建时也会忽略 scope 这个标识,因为内部bean总是匿名的,并且总是用外部bean创建的。不可能单独访问内部bean,也不可能将它们注入到协作bean中,而不是外围bean中。

作为一种极端情况,可以从自定义的 scope  中接收到销毁回调——例如,一个singleton bean中包含一个request-scoped的内部bean。内部bean实例和外部bean一起创建,但是却在request-scoped的生命周期中销毁回调。这种情况并不常见。内部bean通常只是简单的共享包含它们的bean的scoped。

Collections

, , , 和 标签分别设置Java Collection 类型 List, Set, Map, 和Properties, 的属性和参数。下面的例子展示了如何使用它们:


    
    
        
            administrator@example.org
            support@example.org
            development@example.org
        
    
    
    
        
            a list element followed by a reference
            
        
    
    
    
        
            
            
        
    
    
    
        
            just some string
            
        
    

无论是设置map的key或者value还是设置value的值,都可以使用下列标签中的任何一个进行填充【感觉相当于预设一些特殊的或者常用的标签给别人使用】:

bean | ref | idref | list | set | map | props | value | null //这些都是标签
Collection Merging

Spring容器还支持合并 Collection 。开发人员可以定义父标签 , , 或 ,并让子标签 , , 或 继承并覆盖父标签 Collection 的值。也就是说,子 Collection 的值是父 Collection 和子 Collection 的标签合并的结果,子 Collection 的标签覆盖父 Collection 中指定的值。

关于合并的这一节讨论了父子bean机制。下面的例子演示了集合合并:


    
        
            
                administrator@example.com
                support@example.com
            
        
    
    
        
            
            
                sales@example.com
                support@example.co.uk
            
        
    

注意,在子bean definition 的 adminEmails 属性的 元素上使用了merge=true属性。当容器解析并实例化子bean时,实例中会存在一个 adminEmails Properties集合,其中包含子bean的 adminEmails 集合与父bean的 adminEmails 集合合并的结果。下面的清单显示了结果:

administrator=administrator@example.com //继承下来的
sales=sales@example.com
support=support@example.co.uk //重写过的

子 Properties 集合的值集继承父元素中的所有属性元素,并且子元素的支持值覆盖父集合中的值。

Limitations of Collection Merging

不能合并不同的 Collection 类型(例如Map和List),否则将会抛出一个适当的Exception。merge属性必须在较低层次的、继承的子定义上指定。在父集合定义上指定merge属性是多余的,并且不会导致所需的合并。

Strongly-typed collection

由于Java对泛型类型的支持,您可以使用强类型集合。也就是说,可以声明一个Collection类型,使其只能包含(例如)String元素。如果您使用Spring来依赖—将强类型集合注入到bean中,那么您可以利用Spring的类型转换支持,这样强类型集合实例的元素在添加到集合之前就被转换为适当的类型。下面的Java类和bean definition 展示了如何这样做:

public class SomeClass {

    private Map accounts;

    public void setAccounts(Map accounts) {
        this.accounts = accounts;
    }
}

    
        
            
                
                
                
            
        
    

当 something bean的accounts属性准备好注入时,其中的强类型Map元素类型的泛型信息可以通过反射获得。因此,Spring的类型转换基础结构将各种值元素识别为Float类型,并将字符串值(9.99、2.75和3.99)转换为实际的Float类型。

Null and Empty String Values

Spring将属性等的空参数视为空字符串。下面的基于xml的配置元数据片段将email属性设置为空字符串值(“”)。


    

exampleBean.setEmail("");//与上面片段等价

可以通过标签处理空值。如下示例:


    
        
    

exampleBean.setEmail(null);//与上面片段等价
XML Shortcut with the p-namespace

p标签可以替换 标签的内容,但需要引入额外的命名空间,如下所示:



    
        
    

     //两个bean等价

如下示例包含另外两个bean definitions ,它们都引用另一个bean:



    //正常引用
        
        
    

    //使用p命名空间引用

    //被引用的bean
        
    

这个示例不仅包含使用p-namespace的属性值,而且还使用一种特殊的格式来声明属性引用。第一个bean定义使用来创建从bean john到bean jane的引用,而第二个bean定义使用p:spouse-ref="jane"作为属性来完成完全相同的任务。在本例中,spouse是属性名,而-ref部分表示这不是一个直接的值,而是对另一个bean的引用。

【相对于原本的引用方式,p命名空间给我们提供了更多的选择,但就可读性而言,我个人觉得还是原本的标签使用方式更加直观且便于管理】

XML Shortcut with the c-namespace

c标签可以替换 constructor-arg 标签的内容,但需要引入额外的命名空间,如下所示:



    
    

    
    
        
        
        
    

    
    


c:和p:作用类似。

如果构造参数名字不可用的情况下,可以使用索引下标【作为索引必须要由 _ 开头,如下所示:



【相对于原本的引用方式,c命名空间给我们提供了更多的选择,但就可读性而言,我个人觉得还是原本的标签使用方式更加直观且便于管理】

Compound Property Names

在设置bean属性时,可以使用复合或嵌套属性名称,只要路径的所有组件(除最终属性名称外)不为空。考虑下面的bean定义:


    

something bean有一个fred属性,fred属性有一个bob属性,bob属性有一个sammy属性,最后的sammy属性被setter注入值为123。为了使其工作,something 的 fred 属性和 fred 的 bob 属性在bean构建后不能为空。否则,将抛出NullPointerException。

1.4.3. Using depends-on

在定义bean依赖的时候,通常是需要使用ref进行引用加载,但是依赖的加载需要解析,而有些依赖又是间接的不太明显的,所以需要在初始化使用此该标签的bean之前,使用depend -on属性显式地强制初始化一个或多个bean。下面的例子使用depends-on属性来表示对单个bean的依赖:



要表达对多个bean的依赖,请提供一个bean名称列表作为依赖属性的值(逗号、空格和分号是有效的分隔符):

//指定了强制加载但可以不注入
    




原文引用:

The depends-on attribute can specify both an initialization-time dependency and, in the case of singleton beans only, a corresponding destruction-time dependency. Dependent beans that define a depends-on relationship with a given bean are destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can also control shutdown order.

看起来好像挺重要的,后面再回来看看。

1.4.4. Lazy-initialized Beans

默认情况下,ApplicationContext 在进行初始化的过程中,会将所有 singleton bean 创建并进行配置。如果不想要在应用程序启动之时就创建的话,可以在 bean definition 中将该bean标记为 lazy-initialized,这样该bean会在应用第一次请求时才会首次创建实例,而不是刚启动时就创建实例。

在XML中,这种行为由标签上的 lazy-init 属性控制,如下所示:



当上述配置被ApplicationContext使用并且ApplicationContext在启动时,lazy bean不会立即预实例化,而not.lazy bean是会被预实例化的。

但是当 lazy bean 作为 not.lazy bean的依赖时,在 not.lazy bean被预实例化时,同样需要预实例化 lazy bean。

您还可以通过在标签上使用 default-lazy-init 属性来控制容器级别的 lazy-initialization,如下面的例子所示:


    

1.4.5. Autowiring Collaborators

Spring容器可以根据协作bean之间的关系自动装配。您可以通过检查ApplicationContext的内容,让Spring自动为您的bean解析协作者(其他bean)。自动装配有以下优点:

  • 自动装配可以显著减少指定属性或构造函数参数的需要。
  • 自动装配可以随着对象的变更而更新配置。例如,如果您需要向类添加依赖项,那么无需修改配置就可以自动满足该依赖项。因此,自动装配在开发过程中特别有用,而不用在代码库变得更稳定时切换到显式连接。

在基于xml的配置元数据中,您可以使用标签的 autotowire 属性为 bean definition 指定自动装配模式。自动装配功能有四种模式。您可以为每个bean指定自动装配,这样就可以选择要自动装配的bean。下表描述了四种自动装配模式:

ModeExplanation
no(默认)没有自动装配。Bean引用必须由ref 标签定义。对于较大的部署,不建议更改默认设置,因为显式指定协作者会提供更大的控制和清晰度。在某种程度上,它记录了系统的结构。
byName通过属性名自动装配。Spring寻找与需要自动装配的和属性同名的bean。例如,如果一个bean definition 被设置为按名称自动装配,并且它包含一个master属性(也就是说,它有一个setMaster(…)方法),Spring会寻找一个名为master的bean definition,并将它设置为该属性。
byType如果容器中只存在一个属性类型的bean,则允许该属性自动装配。如果存在多个,则会抛出一个 fatal exception ,这表明您可能不会对该bean使用byType自动装配。如果没有匹配的bean,则什么也不会发生(属性没有设置)。
constructor类似于byType,但适用于构造函数参数。如果容器中没有构造函数参数类型的bean,则会引发 fatal exception 。

原文引用:

With byType or constructor autowiring mode, you can wire arrays and typed collections. In such cases, all autowire candidates within the container that match the expected type are provided to satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is String. An autowired Map instance’s values consist of all bean instances that match the expected type, and the Map instance’s keys contain the corresponding bean names.

使用 byType 或 constructor 自动装配模式,可以注入数组和集合类型。在这种情况下,将提供容器中所有匹配预期类型的自动装配候选者,以满足依赖关系。如果预期的键类型是String,您可以自动装配强类型的Map实例。一个自动装配的Map实例的值由匹配预期类型的所有bean实例组成,Map实例的键包含相应的bean名称。

Limitations and Disadvantages of Autowiring

自动装配在项目中最好一直使用。

考虑自动装配的局限性和缺点:

  • property 和 constructor-arg 设置中的显式依赖总是覆盖自动装配所注入的。您无法自动装配简单属性,如基本类型、Strings, 和 Classes(以及此类简单属性的数组)。这是设计上的限制。
  • 自动装配不如显式注入精确。尽管如此,正如前面的表中所指出的,Spring小心地避免猜测,以防出现可能产生意外结果的歧义。spring管理对象之间的关系不再显式地记录。
  • 装配的信息可能无法用于从Spring容器生成文档的工具。
  • 容器内的多个 bean definitions 可以匹配由要自动装配的setter方法或构造函数参数指定的类型。对于数组、集合或Map实例,这并不一定是问题。然而,对于期望单个值的依赖项,这种不确定性不是任意解决的。如果没有唯一的bean定义可用,则会引发异常。

在后一种情况下,你有几个选择:

  • 放弃自动装配选择显示注入。
  • 通过将 bean definition 的autowire-candidate属性设置为false来避免自动装配,具体看下一节。
  • 通过将元素的 primary 属性设置为true,将单个bean定义指定为主要候选。
  • 通过基于注解的配置实现更细粒度的控制。
Excluding a Bean from Autowiring

可以在每一个bean上配置将之从自动装配中排除。如在XML中的将标签中的 autowire-candidate 属性设置为false。容器将会使得该bean definition对不再支持自动装配(包括包括注解配置,如@Autowired)。

autowire-candidate属性被设计为只影响基于类型的自动装配。它不会影响按名称的显式引用,并且自动装配的如果设计为按名称匹配的模式同样可以继续注入。

您还可以基于对bean名称的模式匹配来限制自动装配候选者。顶级标签在其 default-autowire-candidates 属性中接受一个或多个模式。例如,要将自动装配候选状态限制为名称以Repository结尾的任何bean,请提供 *Repository 值。如果需要提供多个模式,可以使用逗号分隔。bean definition 的autowire-candidate属性的显式值true或false总是优先。因此对于这类bean,模式匹配规则不适用。

原文引用:

These techniques are useful for beans that you never want to be injected into other beans by autowiring. It does not mean that an excluded bean cannot itself be configured by using autowiring. Rather, the bean itself is not a candidate for autowiring other beans.

这些技术对于您永远不希望通过自动装配注入到其他bean中的bean非常有用。这并不意味着被排除的bean本身不能通过使用自动装配进行配置。相反,bean本身并不是自动装配其他bean的候选者。【有点混乱,暂时没法理解】

1.4.6. Method Injection 暑期编程PK赛 得CSDN机械键盘等精美礼品!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1016312.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号