后端——框架——容器框架——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数据类型。通过读取配置信息,如何转换为属性的数据类型。
  • 参数的映射过程。构造器的参数,工厂方法的参数,这些映射方式都有三种方式,根据参数的顺序,参数的名称,参数的类型。
原文地址:https://www.cnblogs.com/rain144576/p/12272502.html