• 后端——框架——容器框架——spring_core——《官网》阅读笔记——第一章节2(Bean标签,XML方式)


      bean标签的配置大致可以分为五类

    1. Bean命名的三种方式
    2. Bean创建的三种方式
    3. Bean注入依赖的三种方式
    4. Bean属性值设置,普通类型,集合类型,Empty & NULL
    5. 杂项

      原著中bean的配置主要分为四个部分,

    1. A package-qualified class name:bean对应类的名称
    2. Bean behavioral configuration elements:bean的行为和状态。包括bean的生命周期,作用域等
    3. References to other beans that are needed for the bean to do its work:bean的依赖。
    4. Other configuration settings to set in the newly created objects:其他配置项,例如bean的一些非必备属性。

      此部分内容为官网的1.3和1.4小节的阅读笔记。

    1、命名

      Bean的命名有三种方式,id,name,alias。

    1. id:bean的唯一标识,不能重复,一般都是使用此方式为bean命名。
    2. name:bean的名称,IOC容器允许bean的名称重复,一个bean可以拥有多个名称。不指定时,类名称首字母小写作为name属性的默认值。
    3. alias:bean的别名,一个类可以有多个别名。别名最好有意义。
    <!-- naming bean, bean的命名 -->
     <!-- id方式 -->
     <bean id="user" class="learn.springcore.bean.User"/>
     <!-- name方式 -->
     <bean name="manager" class="learn.springcore.bean.User"/>
     <bean name="vip" class="lean.springcore.bean.User"/>
     <!-- alias方式 -->
     <alias name="manager" alias="boss"/>
     <alias name="manager" alias="projectManager"/>
    

    2、创建方式

      在spring的语义中,创建bean指将bean注入到IOC容器中,由spring根据配置信息创建对象。

      Bean的创建方式有三种,构造器方式,静态工厂方法模式,非静态工厂方法模式。

    2.1      构造器

      当使用类的默认构造器时,设置bean的class属性为类全名即可。

      当使用类的其他构造器时,需要在bean内部配置constructor-arg标签,它代表构造器的参数。参数的映射方式有三种方式,参数的顺序,参数的名称,参数的类型。

    // 假设用户存在三个构造器,默认构造器,User(String name),User(String name, int age)
    <!-- naming bean, bean的命名 -->
    <!-- 默认构造器方式,class属性为类全名即可 -->
    <bean id="user" class="learn.springcore.bean.User" />
    <!--只有单个名称的构造器,使用参数名称映射,name属性的值为参数的名称 -->
    <bean id="user" class="learn.springcore.bean.User">
    	<constructor-arg name="name" value="jack" />
    </bean>
    <!-- 第三个构造器,使用参数顺序映射,0映射为名称参数,1映射为年龄参数 -->
    <bean id="user" class="learn.springcore.bean.User">
    	<constructor-arg index="0" value="jack" />
    	<constructor-arg index="1" value="18" />
    </bean>
    <!-- 第三个构造器,使用参数类型映射,参数的数据类型不予许重复,string映射为名称参数,int映射为年龄参数 -->
    <bean id="user" class="learn.springcore.bean.User">
    	<constructor-arg type="java.lang.String" value="jack" />
    	<constructor-arg type="java.lang.Integer" value="18" />
    </bean>
    

    2.2     工厂静态方法

      工厂静态方法方式下,class属性为工厂方法的类全名,factory-method为静态方法名称,它的返回值为注入bean的类型

    <!-- 静态工厂方式  -->
    <bean id="user" class="learn.springcore.factory.UserFactory" factory-method="getInstance"/>
    

      此时UserFactory类存在getInstance方法,它必须是static修饰,返回值为User对象。

    2.3      非静态方法

      非静态方法方式,class属性不指定,factory-bean属性为工厂类bean标签的ID或者name属性,factory-method为工厂类的方法。此时工厂类必须已注入到容器中。

    <!-- 非静态工厂方法方式 -->
    <bean id="user" factory-bean="userFactory" factory-method="getInstance"/>
    

    3、依赖关系

      配置bean依赖关系的有三种方式,

    • 构造器方式,上面提到过,不再重复。
    • set方法方式。
    • 工厂方法的参数方式。

    3.1     Set方式

      通过Set方式配置依赖关系,本质是配置类的属性,它是将bean标签内部的property标签映射为对象的属性。其中property标签的name属性对应属性名称,value属性相当于给对象的属性赋值。

    <!-- 配置用户 -->
    <bean id="user" class="learn.springcore.bean.User">
    	<!—user的age属性值为21-->
    	<property name="age" value="21" />
    </bean>
    

      age对应User的age属性,value对应age的值,由于age数据类型是Integer,它的映射过程伴随着string--->int的类型转换。

      它与构造器方式的区别在于,

    • Set方式本质是调用类的set方法,构造器本质是调用类的构造器,调用set方法总是发生在调用构造器之后。
    • 如果在创建对象时,存在必备属性,建议使用构造器方式,否则选用Set方式。
    // 构造器方式等价于,必备属性是指在对象创建时,必须指定。
    User user = new User();
    // Set方式等价于
    User user1 = new User();
    user1.setName("name");
    

    3.2    工厂方法的参数

      通过工厂方法参数配置依赖关系,本质是使用工厂静态方法或者是非静态方法创建bean,在其内部使用constructor-arg标签,其中的name属性为参数的名称,value为参数的值。

      constructor-arg也可以使用其他方式,例如参数的顺序,参数的类型。

    4、属性值

    4.1      普通

      当为基本数据类型时,使用property子标签,其中name为属性名,value为属性值

    <property name=”fieldName” value=”fieldVal”>
    

      当为对象时,使用ref子标签,其中bean为对象的名称(ID,name,alias中的任意一个)。此时bean引用的对象必须已注入到容器中。

    <property name=”fieldName” ref=”refBeanID”>

    4.2     集合

      这部分内容是讲,当属性的数据类型为集合相关类时,如何建立XML配置文件与属性的映射关系,name属性映射为对象属性的名称,在映射属性值时,存在差异,示例如下。

    4.2.1    List

    <property name="someList">
           <list>
                  <value>element</value>
                  <ref bean="date"></ref>
           </list>
    </property>
    

    4.2.2  Set

    <property name="someSet">
    	<set>
    		<value>element</value>
    		<ref bean="date"></ref>
    	</set>
    </property>
    

    4.2.3   Map

    <property name="someMap">
    	<map>
    		<entry key="entry" value="just something"/>
    		<entry key="birthDate" value-ref="date"/>
    	</map>
    </property>
    

    4.2.4    Properties

    <property name="someProperties">
    	<props>
    		<prop key="name">jack</prop>
    		<prop key="age">21</prop>
    	</props>
    </property>
    

    4.3   NULL

      当属性值为null时,直接使用null标签,当为空字符串时,标签的value属性值为空串。示例如下:

    <property name="nullProp">
    	<null/>
    </property>
    <property name="name" value=""/>
    

    5、杂项

    5.1      lazy-init

      默认情况下,伴随着容器的创建,会触发容器中所有bean的创建。若想实现按需创建,即在获取该bean的时,才触发bean的创建过程,此时可以设置lazy-init的值为true。

      当bean被其他bean依赖时,该属性会被忽略。例如beanA依赖bean B,此时设置beanB的lazy-init属性为true。容器的创建过程会触发beanA的创建过程,而beanA的创建过程会触发所有它依赖类的创建过程,此时即使beanB的lazy-init为true,它也会被创建。

    5.2      depends-on

      当bean B的创建过程作为bean A创建过程的前置条件时,并且此时A与B不存在依赖关系。即要保证bean B在bean A 之前被创建。此时可以通过设置beanA的depends-on属性,它的值为beanB的ID,此时在创建beanA时,总会先创建beanB,保证创建bean的顺序。

      这种情况通常发生在bean之间存在间接依赖关系。

    5.3      autowire

      当配置依赖关系时,通过constructor,set,工厂方法参数都需要手动配置它们之间的依赖关系,例如property标签的name属性映射为对象的属性名称。

      spring提供一种自动配置方式,建立配置文件到对象属性之间的映射关系。它有四种方式。

    • No:相当于禁用自动配置功能,所有的依赖都需要手动去配置。
    • byName:根据属性名称,例如当User对象存在date属性时,此时若容器中存在id为date的bean标签,会自动获取date,并将返回的对象作为User对象date属性的值
    <bean id="user" class="learn.springcore.bean.User" 
    	  p:birthDate-ref="date"/>
    <bean id="date" class="java.util.Date"/>
    

      这种方式使用ref引用到id为date的bean标签。手动配置。

    <bean id="user" class="learn.springcore.bean.User" />
    <bean id="birthDate" class="java.util.Date"/>
    

      此时在创建User对象,设置birthDate属性时,会获取标识为birthDate的bean。并将返回的对象作为birthDate的属性值。标识可以为id,name,alias。

    • byType:根据属性的数据类型,例如User对象存在birthDate属性,它的数据类型为java.util.Date时,当容器中存在java.util.Date类型的对象时,会将该对象作为属性值。

    • constructor:与byType相似,只不过它只适用于构造器的参数。

      无论是byType,还是byName,当容器中存在多个匹配项时,会报错。

    5.4     autowire-candidate

      当启用自动注入功能时(autowire的属性值不为no),需要查找匹配的bean时,可以设置当前bean标签autowire-candidate属性为false,忽略当前bean。

      例如指定自动注入方式为byName时,创建User对象,设置birthDate属性的值,此时会在容器中查询标识为birthDate的bean,当设置autowire-candidate属性为false时,

      <bean id="birthDate" class="java.util.Date" autowire-candidate="false"/>,查找过程会忽略该bean。

    6、P 前缀 & C前缀

      P字母代表property,它是属性的意思,为了更方便配置bean的属性

      C字母代表constructor,它是构造器的意思,为了更方便配置bean构造器的参数。

      使用它们,首先需要引入schema。

    <!-- p的schema-->
    xmlns:p="http://www.springframework.org/schema/p"
    <!-- c的schema-->
    xmlns:c="http://www.springframework.org/schema/c"
    

      其次需要建立映射关系,

           当属性为基本数据类型时,p:propName它会映射为对象的propName属性,它的值为属性的值。

           当属性为引用数据类型时,p:propName-ref它会映射为对象的propName属性,它的值为容器中引用对象bean的ID或name。 

    7、讨论

      问题1:循环依赖问题?

      答:假设存在A依赖B,B又依赖A的情形,

      当它们以构造器方式去配置依赖关系时,会存在错误,这是因为相互在等待对方构造器的调用。

      当以Set方式去配置时,此时需要首先去创建对象A,或者是对象B,然后在调用它的set方法,此时不会出错,是因为IOC容器首先会去调用A的构造器,或者是B的构造器,然后调用a.setB或者是b.setA,这两个方法之间不存在任何关系,完全可以把构造器的返回的对象A或者B作为这两个方法的参数。

      当以工厂方法参数去配置时,是同理的,因为彼此可以调用默认的构造器,在调用完构造器之后,然后才去调用工厂方法。

      问题2:映射问题

      答:bean本质上就是对应一个Java类,配置bean的过程本质就是将bean映射为Java对象的过程。有四种类型的映射,

    • Bean与Java类的映射关系,通过读取配置信息,如何创建对应的Java类
    • Bean标签属性或者是内部属性与Java类属性的映射关系,通过读取配置信息,如何设置对象类的属性
    • Bean的value,ref如何转换为需要的Java数据类型。通过读取配置信息,如何转换为属性的数据类型。
    • 参数的映射过程。构造器的参数,工厂方法的参数,这些映射方式都有三种方式,根据参数的顺序,参数的名称,参数的类型。
  • 相关阅读:
    服务器做系统备份时失败
    PHPMailer中文乱码问题的解决方法
    html字符串分行显示
    Oracle中取某几个数的最大值最小值
    分布式事务之 Seata
    org.apache.dubbo 2.7.7 服务端处理请求及时间轮(失败重试)
    org.apache.dubbo 2.7.7 服务消费源码
    org.apache.dubbo 2.7.7 服务发布注册源码
    org.apache.dubbo 2.7.x 再聚首
    spring-cloud-gateway 服务网关
  • 原文地址:https://www.cnblogs.com/rain144576/p/12272502.html
Copyright © 2020-2023  润新知