`
1028826685
  • 浏览: 938385 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类

Spring 5 中文解析之核心篇-IoC容器

阅读更多

 

 

关于本书

本书

本书编写主要目的在于翻译官方spring.io关于SpringFramework模块文档之核心篇,但是本书不仅仅是简单的翻译,我会根据相应的模块给出一些代码的操作实践以及给出相应的源码分析,SpringFramework文档我个人认为在所有开源框架中算是写得最好的了,But如果对于初学者或者是实践经验较少的小伙伴来说还是比较困难的。这里不仅仅是文档全是英文形式而且根据文档的概述是比较难理解和应用到实践项目开发中,这里需要开发人员积累了相应的项目实践经验才行。So我在翻译SpringFramework过程中会不断编写相应的示例代码、结合文档和源码分析达到更好的理解。在后面的书中我可能会翻译现在比较流行的微服务框架SpringBoot 、SpringCloud以及Spring的其他模块比如:SpringDataSpringSessionSpringSecurity 等,SpringFramework在整个Spring体系中起着基石的作用,SpringBoot基于SpringFramework进行了相应的拓展包括:自动化配置外部化配置组件化(start模式)等,而SpringCloud基于SpringBoot对整个微服务体系的服务治理、服务注册发现、统一配置中心等做了相关的集成和统一相关的抽象例如: Spring Cloud Commons等。对应SpringFramework这块主要分为以下模块来解析:Spring核心测试数据存储Web ServletWeb Reactive集成

 

版本

当前选择的版本Version 5.2.7.RELEASE进行分析。

 

约束

  • 使用字体加粗对重点关键字进行标注
  • 使用灰色线框对专业术语进行标识
  • 本文使用不同层级对文档结构进行描述
  • 文章的一级、二级分类尽量保存英文不做翻译(能够帮助读者能够快速定位原文位置)
  • 示例代码地址:https://gitee.com/newitman/SpringFramework5.2.6.git
  • 本书开始编写时间2020-05-05

 

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。

博客地址:http://youngitman.tech

CSDN:https://blog.csdn.net/liyong1028826685

微信公众号: 

 

概述

 

Spring使得开发人员更加容易的创建企业级应用程序,它提供了在企业Java生态技术栈中的任何技术体系,同时也提供了GroovyKotlin对JVM的支持,并且可以根据应用程序的需要灵活地创建多种体系结构,从Spring Framework 5.1开始Spring需要JDK1.8+,同时也提供了对JDK 11 LTS开箱即用的支持。Java SE 8 update 60作为Java 8最低的补丁版本被建议使用,但是一般推荐使用最近发布的补丁版本。

Spring支持广泛的应用场景。在大型企业中,应用程序可能长时间的存在,而且需要运行在JDk上,同时应用程序的升级维护生命周期不受开发人员的控制。其他可能作为单独的jar运行或者嵌入式运行,也可能运行在云环境中。也可能是不需要服务器的一个独立的应用程序(例如:批处理、集成负载)。

GroovyKotlinJava一样可以编译成JVM支持的字节码格式,运行在JVM中。

Spring是一个开源的框架。Spring拥有一个非常强大和活跃的社区,它提供了一个范围广泛的实际应用案例的持续反馈。这有助于Spring长时间的成功发展。

 

What We Mean by "Spring"

 

Spring术语在不同上下文意义是不同。在这里Spring就是指SrpingFramework项目本身。然而随着时间的推移,其他的Spring项目被构建在SrpingFramework基础上。大多数情况下,我们所说的Spring是包括整个项目体系。这篇文档主要聚焦在Spring Framework框架本身。

SpringFramework分为多个模块。应用程序根据需要选择合适的模块。核心容器的模块是核心包括:配置模型、依赖注入机制。除此之外,SpringFramework提供一些基础的为不同应用架构、消息、事务数据和持久化、web提供支持。它也包括了基于Servlet基础的SpringMVC的web框架和支持WebFluxreactive编程模型的web框架。

关于模块需要注意的:Spring的这些框架jar包允许被部署到JDK9的模块路径。为了在支持Jigsaw的应用程序中使用,Spring Framework 5 jar附带了自动模块名称清单条目,这些清单条目定义了与jar无关的稳定语言级别的模块名称(spring.corespring.context等)名称(这些jar遵循相同的命名模式,用-代替.,例如spring-corespring-context)。当然,Spring的框架jar可以在JDK 8和9的类路径上正常工作。

 

History of Spring and the Spring Framework

 

介于早期的J2EE规范过于复杂,在2003年Spring诞生了,尽管有些人认为Java EE和Spring竞争,但事实上Spring是Java EE的补充。Spring编程模型不包含Java EE平台规范。相反,它精心选择各个规范进行集成

SpringFramework同时也支持依赖注入(JSR 330)和通用注解规范 (JSR 250) ,应用程序开发人员可以选择使用这些规范来代替Spring框架提供的特定于Spring的机制。

SpringFramework5.0后,Spring的最低要求 Java EE 7(Servlet 3.1+JPA 2.1+)同时提供了开箱即用的集成Java EE 8最新的API (JSON Binding API),这样使得Spring能够更好的兼容例如:Tomcat 8 、 Tomcat 9WebSphere 9JBoss EAP 7服务容器。

随着时间的推移,J2EE在应用开发中的作用已经发生改变。在J2EE和Spring的早期,应用程序需要部署到应用服务器上。如今,在SpringBoot的帮助下,这些应用可以通过devops和友好的方式被创建,同时通过Servlet容器的嵌入和一些很小的改变。从SpringFramework5.0开始WebFlux的应用程序甚至不需要直接使用Servlet的API并且能够直接运行在非Servlet容器服务器上。

Spring不断的创新和发展。除了Spring Framework,还有其他项目,例如Spring BootSpring SecuritySpring DataSpring CloudSpring Batch等。请务必记住,每个项目都有自己的源代码存储库,问题跟踪程序和发布节奏。请查看spring.io/projects 罗列了完整的Spring项目清单。

 

Design Philosophy(哲学)

 

当你在学习框架的时候,最重要的是不仅仅知道它能做什么,而且要遵循什么原则。以下是Spring框架的指导原则。

  • Spring提供在各个级别的选择。让开发者尽可能的推迟对设计的抉择。例如:你可以在不更改代码的情况下使用配置来切换数据的持久化方案。对于其他许多基础架构问题以及与第三方API的集成也是一样可以通过配置来调整。
  • 容纳不同的观点。Spring支持灵活性,对于事情应该如何完成没有任何意见。它支持具有不同视角的广泛应用程序需求(备注:意思是Spring设计相当灵活、对应怎样去完成逻辑处理Spring不会干涉)
  • Spring保存了强的向后兼容性。Spring的演进被精心的管理以确保在不同版本间的变更尽量小。Spring非常小心的选择JDK和第三方库的版本,以方便维护依赖于Spring的应用程序和库。
  • Spring的API精心设计。Spring花费了大量的时间和精力来设计API,并在许多版本和很多年中都适用的API。
  • 高标准的代码质量要求。Spring框架非常强调有意义的、当前的和准确的javadoc。它是极少数可以代码结构整洁且程序包之间没有循环依赖关系的项目之一。

 

Spring核心

 

The IoC Container

 

1.1 Spring IoC容器和bean

 

这章节主要包括了SpringFrameworkIoC容器的控制反转的原理。IoC也被称作依赖注入(DI)。这是一个对象仅通过构造函数参数、工厂方法的参数或对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即与之一起工作的其他对象)的过程。此过程从根本上讲是通过使用类的直接构造或诸如服务定位器模式之类的机制来控制其依赖项的实例化或位置的bean的逆过程(因此称为Control Inversion)。(备注:大白话的意思就是为实例对象注入依赖的实例,注入方式包括构造函数注入、对象属性注入、setXXX方法注入等。)

org.springframework.beansorg.springframework.context包是SpringFramework容器的基础。BeanFactory接口提供一个高级的配置机制能力,可以管理任何类型的对象。ApplicationContextBeanFactory的子接口。增加了如下能力:

  • 更容易的集成SpringAOP特性
  • 消息资源处理(国际化)
  • 事件发布器
  • 应用层特定的上下文,例如:对应web应用上下文WebApplicationContext

简要来说,BeanFactory提供了配置框架和基本的功能,ApplicationContext提供了更多的企业级功能。ApplicationContext是一个完整的BeanFactory的超级,在这章节中只是用来描述为Spring的容器。更多的ApplicationContext替换BeanFactory的使用查看BeanFactory

Spring中,构成你的应用程序的骨架和被容器所管理的对象被称为beanbean是被Spring容器所实例化、包装、和管理的对象。bean也是在我们的应用程序中许多对象中之一。beanbean之间的依赖关系是通过容器的配置元数据反映的。

参考示例代码: com.liyong.ioccontainer.IoCContainer

 

1.2 Spring IoC容器概述

 

org.springframework.context.ApplicationContext接口代表SpringIoC容器,同时有责任对这些bean的实例化、配置和组装。容器通过获取配置元数据知道哪些对象需要进行实例化、配置和组装。这些配置元数据通过xml、java的注解或者java的配置(Java Config)。它允许你去表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。

Spring中提供了一些关于ApplicationContext的实现。在一个独立的应用程序中,一般通过ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext去创建容器实例。而XML作为传统的定义配置元数据的方式,同时你可以引导容器去使用Java的注解或者Java Config作为元数据格式,通过提供少量的XML配置去声明激活这些附加元数据配置格式。

在大多数应用场景下,显示的实例化一个或多个Spring IoC容器实例是没有必要的。例如:在Web应用场景中,在应用程序web.xml文件中简单的xml配置描述通常就足够。如果使用Spring Tools for Eclipse工具,我们将非常容易的创建样板配置。

下面通过图片来展示Spring是怎样工作的,我们的应用程序类(业务类)与配置元数据结合在一起,在ApplicationContext被创建和实例化后,我们将拥有一个完整的配置和可执行的应用系统。

container magic

 

1.2.1 配置元数据

 

上图所示,Spring容器获取配置元数据。那么这些元数据是怎样被表示或者是怎样配置的呢,作为一个开发人员,在你的应用程序中去告诉Spring容器怎样去实例化、配置和组装这些对象。

XML格式作为一种传统的配置元数据方式,在这个章节中大部分内容使用这些关键概念和特性。

基于XML的配置元数据不是唯一被允许使用的配置方式。Spring容器本身是和这些配置元数据是解偶的。现在,大多数的开发人员使用Java base configuration作为Spring应用的配置方式。

关于更多的Spring容器的元数据配置方式以下罗列出来:

  • 基于注解的配置方式:从Spring 2.5开始引入对注解元数据配置的支持
  • 基于Java-base configuration方式:从Spring 3.0开始,SpringJavaConfig项目成为SpringFramework的核心部分,许多的特性被提供。因此,我们可以使用Java Config的方式定义外部bean而不是XML文件。我们可以使用这些新特性注解 例如: @Configuration、 @Bean@Import 和@DependsOn

Spring配置组成至少通常超过一个bean的定义被容器管理。基于XML的配置元数据将这些bean配置为顶级元素内的元素。Java Config通常使用@Bean注解在方法上同时所在的类被@Configuration标注。

这些bean的定义对应到真实的bean对象实例同时我们的应用程序由这些对象实例所构建。比如:我们定义的service层数据存储层(dao)展示层 比如:StrutsAction实例、HibernateSessionFactories实例、JMSQueues等等。典型地,不需要在容器中配置细粒度的域对象,因为通常由DAO和业务逻辑负责创建和加载域对象。但是,你可以使用SpringAspectJ的集成来配置在IoC容器控制范围之外创建的对象。

以下使用基于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>
</beans>
 

参考示例代码:com.liyong.ioccontainer.XmlIocContainer

  • id属性表示一个bean的唯一id
  • class属性表示这个bean的全路径类型名称例如:com.liyong.ioccontainer.ConfigruationService

 

1.2.2 容器实例化

 

ApplicationContext构造函数提供了一个或多个字符串路径参数,让容器去加载外部资源的配置元数据,例如:本地文件系统或者Java 类路径等等。

 
 
 
 
 
 
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");//加载services.xml和daos.xml配置元数据
 

在我们学习了关于Spring IoC容器后,我们可能想知道更多关于Resource的抽象,Resource提供了一个便利的机制去通过URI语法定义的位置读取一个输入流。特别地,Resource被用于构建应用程序的上下文。Application上下文和Resource路径

以下给出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>
 

以下显示数据获取层dao.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类和数据存储层JpaAccountDaoJpaItemDao对象组成(以JPA的对象关系映射为标准)。属性名称元素引用JavaBean的属性名称,并且ref元素引用其他bean定义的名称。id和ref之间的联系表达了协作对象的依赖性。更多的关于对象依赖的配置查看Dependencies

 

  • 组成基于XML的配置元数据

     

    配置元数据可以跨多个XML配置文件。通常情况下,每个独立的XML配置文件代表项目架构中的逻辑层或者模块。

    你可以使用ApplicationContext构造函数从这些配置的XML片段中加载bean的定义。这个构造函数可以使用多个Resource来定位资源,在上面的例子中可以查看。或者,使用一个或多个标签元素从其他的XML配置文件中加载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从3个文件中被加载分别是:services.xmlmessageSource.xmlthemeSource.xml。所有被导入文件路径是相对应导入文件位置。(备注:大白话就是相对于当前导入文件的路径),因此services.xml必须在导入文件相同的目录或者类路径下,而messageSource.xmlthemeSource.xml必须在导入文件下的resources路径。正如你所看到/被忽略。但是,鉴于这些路径是相对的,最好不要使用斜线。

    一种可能的使用方式使用../去引用父目录文件,但是不是推荐的。这样做会导致当前应用对外部文件的依赖。特别是,这种引用方式在使用classpath:URL组合是不被推荐(例如:classpath:../services.xml),运行时解析过程在其中选择最近的类路径根,然后查看其父目录。类路径配置的更改可能导致选择其他错误的目录。

    我们应该总是使用全限定资源路径去替换相对路径:例如:file:C:/config/services.xml或者classpath:/config/services.xml。但是请注意,你正在将应用程序的配置耦合到特定的绝对位置。通常最好对这样的绝对位置保留间接使用,例如通过在运行时针对JVM系统属性解析的${…}占位符。

    名称空间本身提供了import指令特性。除了普通bean定义之外,Spring提供的XML名称空间选择中还提供了其他配置功能-例如:contextutil命名空间

 

  • Groovy的bean定义

     

    为外部配置元数据例举更进一步的例子,bean的定义能够使用SpringGroovy语言定义来表达(可以从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定义方式并且支持SpringXML命名空间配置。这种方式允许我们通过importBeans指令去导入XMLbean定义。

参考示例代码:com.liyong.ioccontainer.ImportXmlIocContainer

 

1.2.3 容器使用

 

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

ApplicationContext允许我们去读取bean的定义和获取bean实例对象,举例子:

 
 
 
 
 
 
// 创建容器和加载bean定义
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// 获取bean实例
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
 

使用Groovy配置,引导非常的类似。但是它是不同的Context的实现。举例子:

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

最灵活的变体是GenericApplicationContext结合了reader的代理-例如:通过XmlBeanDefinitionReader读取XML文件中的配置信息。举例子:

 
 
 
 
 
 
GenericApplicationContext context = new GenericApplicationContext();
//加载xml中配置元数据
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
 

我们也可以使用GroovyBeanDefinitionReader加载Groovy配置文件。举例子:

 
 
 
 
 
 
GenericApplicationContext context = new GenericApplicationContext();
//加载groovy配置元数据
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
 

我们也可以在相同的ApplicationContext中混合或者匹配一个reader的代理,去读取不同配置源的bean定义配置信息。

我们也可以使用getBean()方法去获取我们的bean实例对象。ApplicationContext接口同时提供了一些其他的方法获取bean实例,但是,理想情况下,我们的代码不要直接使用它们。确实,我们的应用程序代码不应该直接调用getBean()方法,这样就不会对Spring的API进行耦合(备注:个人观点,在目前来看Spring已经是容器管理的规范和标准了,使用API会对应用程序耦合这个两说,个人觉得是没有问题的,除非你还想换掉底层容器)。例如:Spring集成的Web框架(一般指SpringMVC)提供了变体的Web框架组件的依赖注入controllers(Controller) 和 JSF-managed 的bean对象,同时允许我们通过元数据声明一个指定bean的依赖(例如注解注入:@Autowired@Resource)。

 

1.3 Bean的概述

 

Spring IoC容器管理一个或多个bean对象。这些bean是通过我们提供的容器和配置元数据所创建的(例如:通过在XML文件中定义的)。

Spring IoC容器自身内部,这些bean的定义是被BeanDefinition对象所描述,包括了一些元数据信息:

  • 包限定类名:典型地,bean被定义的实际实现类
  • bean的行为配置元素,bean在容器中应该是怎样的行为状态(scopelifecycle callbacks,等等)
  • 引用bean完成工作所需要的其他bean。这些引用bean被称为协同者或者依赖项。
  • 在新创建的对象中去配置其他配置的设置 例如:在一个bean中使用连接数或池大小现在来管理一个连接池。

这个配置元数据转移到属性配置集合中构建每一个bean的定义。下面这个表格描述了这些属性:

属性解释
Class(配置Class信息) Instantiating Beans
Name(bean名称) Naming Beans
Scope(bean的范围) Bean Scopes
Constructor arguments(构造参数) Dependency Injection
Properties(bean的属性) Dependency Injection
Autowiring mode(自定注入模式) Autowiring Collaborators
Lazy initialization mode(是否为懒加载) Lazy-initialized Beans
Initialization method(bean初始化回调方法) Initialization Callbacks
Destruction method(bean销毁回调方法) Destruction Callbacks

此外bean的定义也包括了怎样去创建一个指定bean的信息,ApplicationContext的实现允许在容器外部创建的bean注册到容器中。这个是通过获取ApplicationContextBeanFactory通过getAutowireCapableBeanFactory()方法,返回一个BeanFactoryDefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(..)registerBeanDefinition(..)方法支持去注册bean信息。但是,典型的应用程序只能与通过常规bean定义元数据定义的bean一起使用。(备注:一般不对Spring进行拓展是不会使用到)

bean元数据和手动提供的单例bean实例需要尽可能早地被注册,以便容器在自动装配和其他内省步骤期间正确地推断它们。覆盖存在的元数据和单例实例在某些角度是被支持的,新对象在运行时被注册官方是不支持的并且可能导致并发获取异常、容器中的bean状态不一致,或者两种情况都有。

参考示例代码:com.liyong.ioccontainer.starter.RegisterBenDefination

 

1.3.1 Bean的命名

 

Spring IoC容器中的每个bean都有一个或多个唯一的标识。这些标识在同一个容器中必须是唯一的。一个bean通常只有一个标识。但是,如果bean需要多个标识可以考虑使用别名的方式。

在基于XML的元数据配置中,我们可以使用id属性、name属性或者两者都使用。id属性可以精确的指定唯一的id。按照惯例,这些名称可以是数字字母,但是也可以包含特定的字符。如果我们想为bean引入其他的别名,可以指定name属性通过, 、: 、或者空格来分割多个别名。需要注意的是,在Spring3.1之前的版本中,id属性被定义作为xsd:ID类型,约束可能的字符。在Spring3.1后,被定义为xsd:string类型。值得注意:Bean ID唯一性仍由容器强制执行,尽管不再由XML解析器执行。

Spring没有强制要求我们提供一个beanid或者name属性。如果我们没有显示的提供id或者name属性,Spring容器会为bean生成一个唯一的名称。但是,如果我们想通过bean名称去引用可以通过使用ref元素或者是使用服务定位查找,必须提供一个bean的名称。如果不提供bean名称的动机可能是与使用内部bean自动装配协同者有关。

Bean命名约定

当给bean的属性命名的时候,使用Java中的标准命名规范。也就是,以小写字母开始驼峰的命名方式。例如:accountManager、 accountService、 userDaologinController

统一的命名约束能够使我们更容易的去阅读和理解。如果我们使用Spring AOP,当应用通知到通过名称所关联的bean集合是有用的。

通过在类路径中进行组件扫描,Spring会按照前面描述的规则为未命名的组件生成Bean名称:从本质上讲,采用简单的类名称并将其初始首字符转换为小写。但是,在(不寻常的)特殊情况下,如果有多个字符并且第一个和第二个字符均为大写字母,则会保留原始大小写。这些规则与java.beans.Introspector.decapitalize(Spring在此使用)定义的规则相同。

 

  • 在Bean定义之外别名Bean

     

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

    指定实际定义bean的所有别名并不总是足够的,有时需要为在别处定义的bean引入别名。在大型系统中通常是这种情况,在大型系统中,配置在每个子系统之间分配,每个子系统都有自己的对象定义集。在基于XML配置元数据中,我们可以使用标签元素来完成。举例子:

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

    在这个例子中,一个bean(相同容器中)的名称fromName被定义一个别名toName

    例如:subsystemA系统通过配置元数据subsystemA-dataSource引用一个DataSource数据源。subsystemB系统通过配置元数据subsystemB-dataSource引用一个DataSource数据源。当主应用程序组合使用这两个系统,主应用程序通过myApp-dataSource名称引用DataSource 。总共有三个名称引用相同的对象,我们可以增加别名定义配置元数据:

     
     
     
     
     
     
    <!--myApp-dataSource定义一个别名subsystemA-dataSource-->
    <alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
    <!--myApp-dataSource定义一个别名subsystemB-dataSource-->
    <alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
     

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

    Java-Configuration

    如果使用JavaConfig方式配置bean,@Bean注解也提供了别名的支持。查看 @Bean 使用详情

    参考示例代码:

    XML配置方式:com.liyong.ioccontainer.starter.XmlAliasIocContainer

    JavaConfig方式:com.liyong.ioccontainer.starter.AnnotationAliaseIoCContainer

 

1.3.2 bean的实例化

 

bean定义实际上是创建一个或多个bean对象的模版。容器通过被命名的bean查找模板,当从容器中请求对象时通过bean定义的元数据封装去创建(或获取存在的)一个真实的对象。

如果使用基于XML的配置元数据,我们通过在标签元素指定Class属性来进行实例的初始化(在BeanDefinition实例中指定Class属性)。这个Class属性通常是必填的。(更多查看 实例工厂方法 和 继承Bean定义)我们可以使用两种Class属性的一种方式:

  • 典型地,在容器本身直接的创建bean的地方,通过class的构造函数反射地构建bean实例,类似在java代码中new操作。
  • 指定真实类去包含静态的工厂方法,调用静态方法创建这个对象,在不太常见的情况下,容器在类上调用静态工厂方法来创建Bean。对象类型从静态工厂方法的调用被返回,可能返回相同的类或其他的类。

内部类名字

如果想配置一个静态的嵌入的类定义,我们必须使用嵌入类的二进制名。

例如:如果有一个类叫做SomeThingcom.example包中,并且这个SomeThing类有一个静态的嵌入类叫OtherThing,这个class属性的值在bean定义中是com.example.SomeThing$OtherThing

 

参考示例代码:com.liyong.ioccontainer.starter.InnerIoCContainer

 

  • 构造函数初始化

    当我们通过构造函数方法创建bean时,所有常规的类是可以被Spring使用或兼容的。也就是说开发的类不需要实现特定的接口或者特定的编码风格。一个简单的指定bean就可以满足需求。然而,这取决于你指定bean依赖的IoC类型,你需要一个默认的构造函数。(也就是说类需要一个默认的构造函数)

    实际上Spring IoC容器能够管理你想管理的任何类。它不会限制管理的是否是真正的JavaBean。大多数Spring用户更喜欢真实的JavaBean,它们仅具有默认(无参数)构造函数,并根据容器中bean的属性建模适当的settergetters方法。在我们的容器中也可以有更多的外来的非bean格式的类。例如:你去使用一个绝对的不符合JavaBean规范的遗留的连接池,Spring也可以管理好它。

    通过基于XML配置的元数据,你可以指定bean的类如下:

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

    更多的关于提供多个参数的构造函数机制和在对象属性设置对象实例后被构造,可查看依赖注入

  • 静态工厂方法实例化

    当通过静态工厂方法定义一个bean时,使用class属性去指定这个类包含这个static工厂方法并用factory-method属性去指定工厂方法的名称。你应该去调用这个方法并且返回一个存活对象,随后将其视为已通过构造函数创建。这种bean定义的一个用途是在遗留代码中调用静态工厂。

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

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

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

    参考代码:com.liyong.ioccontainer.starter.XmlStaticFactoryMethodIocContainer

  • 实例工厂方法实例化

    类似通过静态工厂方法实例化,初始化一个实例工厂方法调用一个存在bean的非静态方法,从bean容器中创建一个新bean实例。为了使用这个机制,class属性设置为空并且在factory-bean属性中设置一个在当前容器bean的名称,这个实例方法被调用创建一个对象实例。通过设置factory-method属性指定工厂方法名称。

     
     
     
     
     
     
    <!-- the factory bean, which contains a method called createInstance() -->
    <bean id="serviceLocator" class="examples.DefaultServiceLocator">
        <!-- inject any dependencies required by this locator bean -->
    </bean>
    <!-- factory-bean:指定bean名称 factory-method:指定创建bean的方法 -->
    <bean id="clientService"
        factory-bean="serviceLocator"
        factory-method="createClientServiceInstance"/>
     

    下面是使用示例的类定义

     
     
     
     
     
     
    public class DefaultServiceLocator {
        private static ClientService clientService = new ClientServiceImpl();
      //非静态方法
        public ClientService createClientServiceInstance() {
            return clientService;
        }
    }
     

    一个工厂类可以有多个工厂方法:

     
     
     
     
     
     
    <bean id="serviceLocator" class="examples.DefaultServiceLocator">
        <!-- inject any dependencies required by this locator bean -->
    </bean>
    <bean id="clientService"
        factory-bean="serviceLocator"
        factory-method="createClientServiceInstance"/>
    <bean id="accountService"
        factory-bean="serviceLocator"
        factory-method="createAccountServiceInstance"/>
     

    上面例子对应类定义:

     
     
     
     
     
     
    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)。查看依赖和配置详情

    Spring文档中,factory bean引用一个在Spring容器中配置的bean并且通过一个实例或者静态工厂方法创建对象。对比,FactoryBean是特定于Spring的FactoryBean实现类。

    参考代码:com.liyong.ioccontainer.starter.XmlFactoryMethodIocContainer

  • 确定bean的运行时类型

    bean的运行时类型确定是不容易的。在bean的元数据定义中指定类仅仅是初始类的引用,潜在地,结合声明的工厂方法或者存在一个FactoryBean类可能导致bean的运行时类型不同,或者在实例级别工厂方法没有被设置(通过指定factory-bean名称替换)。此外,AOP代理可以用一个基于接口的代理包装一个bean实例,该代理只公开有限的目标bean的实际类型。(备注:由于存在代理导致运行时真实类型在运行期间才能确定)

    推荐的方式查找关于特定bean的运行时类型是去调用BeanFactory.getType方法并指定bean的名称。考虑了以上所有情况并通过指定相同bean名称调用BeanFactory.getBean返回对象类型。

     

分享到:
评论

相关推荐

    Spring源代码解析(一):IOC容器.doc

    在Spring源代码解析的第一部分,我们将聚焦于IOC容器,特别是BeanFactory接口,它是所有Spring容器的基础。 BeanFactory接口是Spring的基石,它定义了基本的容器操作,如获取Bean、检查Bean是否存在、确定Bean的...

    Spring-ioc-jar

    Spring IOC,全称为Inversion of Control,中文常被称为“控制反转”,是Spring框架的核心特性之一。这个概念在软件设计中引入了一种新的依赖管理方式,它将对象的创建和管理权交给了容器,使得开发者可以更专注于...

    Spring-IoC 容器 - v1.01

    Spring的IoC容器是整个框架的核心,它负责管理对象的生命周期和依赖关系。容器通过读取配置元数据(通常是XML或Java注解),知道如何创建、初始化和装配Bean。开发者无需在代码中硬编码依赖关系,而是声明性地在配置...

    Java-Spring-SpringIoC容器-SpringIoC的学习

    在Java Spring框架中,Spring IoC(Inversion of Control,控制反转)是核心特性之一,它使得应用程序的组件之间的依赖关系不再由代码直接管理,而是交由Spring IoC容器负责。这种设计模式降低了代码间的耦合,提高...

    Spring IOC容器实现分析.pdf 下载

    《Spring IOC容器实现分析》 在Java开发领域,Spring框架无疑是使用最为广泛的轻量级框架之一,其中的核心组件就是IOC(Inversion of Control)容器。本文将深入剖析Spring的IOC容器,理解其工作原理和重要功能,以...

    Spring-IOC实现

    - Spring提供了测试支持,如@Test注解的JUnit测试和@SpringBootTest注解的Spring Boot测试,方便进行集成测试和单元测试,确保IOC容器内的Bean正确工作。 以上就是Spring-IOC的基本实现和相关知识点,包括注解和...

    Spring源码解析4章150页+Spring3.2.4中文注释源码

    5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 Spring事务源码解析 需要其他源码请私信我

    Spring的IoC容器初始化源码解析

    ### Spring的IoC容器初始化源码解析 #### 一、Spring框架的核心——IoC容器 Spring框架是一个开源的轻量级Java开发框架,其核心功能是IoC(Inversion of Control,控制反转)容器和AOP(Aspect Oriented ...

    Spring源代码解析(二):IoC容器在Web容器中的启动.doc

    当我们在Web环境中运行Spring应用时,IoC容器需要在Web容器(如Tomcat、Jetty等)中启动并运行。这个过程涉及到一系列的初始化步骤,确保Spring能够正确地与Web容器集成。 首先,`WebApplicationContext`是`...

    Spring中IoC优点与缺点解析

    Spring 中 IoC 优点与缺点解析 IoC(Inversion of Control)是 Spring 框架中的一种设计模式,它的主要思想是将对象的创建和管理交给容器,从而解耦合对象之间的依赖关系。今天,我们将详细解析 IoC 的优点和缺点。 ...

    spring-demo10-注解-IOC.zip

    在IT行业中,Spring框架是Java企业级应用开发的首选框架之一,因其强大的功能和灵活性而备受推崇。在Spring中,依赖注入(Dependency Injection,简称DI)是核心特性,而注解(Annotation)则是实现DI的一种现代化...

    Spring-IOC丐版

    在这个名为"Spring-IOC丐版"的项目中,我们将深入探讨Spring框架的核心组件——IOC容器的基础实现。 IOC,即控制反转,是一种设计模式,它的主要思想是将对象的创建和管理权交给一个外部容器,而不是由对象自身负责...

    深入理解java的spring-ioc的使用.docx

    3. **依赖注入**:依赖注入是Spring IoC的核心机制之一,通过构造器注入、setter注入或基于字段的注入等方式,Spring IoC容器可以在运行时动态地为对象提供所需的依赖。 #### 三、Spring-IoC的使用方法 1. **把...

    Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程.doc

    Spring 框架系列(7)- Spring IOC 实现原理详解之 IOC 初始化流程 本文将详细解释 Spring 框架中的 IOC(Inversion of Control,控制反转)实现原理之 IOC 初始化流程。IOC 是一种软件设计模式,用于将软件系统中...

    spring-framework-1.0-with-dependencies.zip

    1. **spring-beans**:这是Spring的核心模块,实现了IoC容器,负责管理对象的生命周期和依赖关系。 2. **spring-context**:扩展了spring-beans,引入了ApplicationContext接口,提供了一种更高级的容器,可以处理...

    手写一个SpringIoc容器

    在实现自定义的Spring IOC容器时,我们需要关注以下几个核心知识点: 1. **Bean的定义与注册**:首先,我们需要创建一个表示Bean的类或接口,包含Bean的ID、类名等信息。Bean的定义可以通过XML配置文件、注解或者...

    Spring IoC简单示例-注解配置-Maven构建

    Spring IoC容器通过解析XML配置文件或使用注解来识别对象及其依赖关系,并在运行时自动装配这些对象,这就是依赖注入。 在Spring中,注解配置是取代传统XML配置的一种方式,它使得代码更加简洁、易读。例如,我们...

    spring ioc

    Spring 是一个广泛应用的 Java 应用开发框架,其核心特性之一就是IOC,它极大地简化了软件组件之间的依赖管理。在本文中,我们将深入探讨 Spring IOC 的概念、工作原理以及如何在实际项目中应用。 首先,理解 IOC ...

    spring-framework-5.0.0.RELEASE-dist.zip

    Spring的核心模块提供了如IoC(Inversion of Control,控制反转)容器、AOP代理、事件传播、资源处理等功能。同时,它还可能包含Spring与其他技术的集成,如Spring JDBC、Spring ORM(对象关系映射)用于数据库操作...

    Spring IoC容器实现的结构分析

    Spring IoC容器是Spring框架的核心,它负责管理应用对象的生命周期和依赖关系。通过对IoC(Inversion of Control,控制反转)的实现,Spring容器将对象的创建和组装工作从应用代码中分离出来,使得应用更易于测试和...

Global site tag (gtag.js) - Google Analytics